home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / pyos2bin.zip / Demo / sgi / gl / mclock.py < prev    next >
Text File  |  1996-11-27  |  19KB  |  737 lines

  1. #! /usr/bin/env python
  2.  
  3. # "M Clock"
  4. #
  5. # An implementation in software of an original design by Rob Juda.
  6. # Clock implementation: Guido van Rossum.
  7. # Alarm and Gong features: Sape Mullender.
  8. #
  9. # XXX TO DO:
  10. # add arguments to specify initial window position and size
  11. # find out local time zone difference automatically
  12. # add a date indicator
  13. # allow multiple alarms
  14. # allow the menu to change more parameters
  15.  
  16. import sys
  17.  
  18. from gl import *
  19. from GL import *
  20. from DEVICE import *
  21. import time
  22. import getopt
  23. import string
  24. import os
  25. from math import pi
  26. import math
  27.  
  28. FULLC = 3600        # Full circle in 1/10-ths of a degree
  29. MIDN = 900        # Angle of the 12 o'clock position
  30. R, G, B = 0, 1, 2    # Indices of colors in RGB list
  31.  
  32. HOUR = 3600        # Number of seconds per hour
  33. MINUTE = 60        # Number of seconds per minute
  34.  
  35. class struct: pass    # Class to define featureless structures
  36. Gl = struct()        # Object to hold writable global variables
  37.  
  38. # Default constants (used in multiple places)
  39.  
  40. SCREENBG = 127, 156, 191
  41. NPARTS = 9
  42. TITLE = 'M Clock'
  43.  
  44. # Set timezone, check for daylight saving time
  45. TZDIFF = time.timezone
  46. if time.localtime(time.time())[-1]:
  47.     TZDIFF = time.altzone
  48.  
  49. # Default parameters
  50.  
  51. Gl.foreground = 0    # If set, run in the foreground
  52. Gl.fullscreen = 0    # If set, run on full screen
  53. Gl.tzdiff = TZDIFF    # Seconds west of Greenwich (winter time)
  54. Gl.nparts = NPARTS    # Number of parts each circle is divided in (>= 2)
  55. Gl.debug = 0        # If set, print debug output
  56. Gl.doublebuffer = 1    # If set, use double buffering
  57. Gl.update = 0        # Update interval; seconds hand is suppressed if > 1
  58. Gl.colorsubset = 0    # If set, display only a subset of the colors
  59. Gl.cyan = 0        # If set, display cyan overlay (big hand)
  60. Gl.magenta = 0        # If set, display magenta overlay (little hand)
  61. Gl.yellow = 0        # If set, display yellow overlay (fixed background)
  62. Gl.black = 0        # If set, display black overlay (hands)
  63. Gl.colormap = 0        # If set, use colormap mode instead of RGB mode
  64. Gl.warnings = 0        # If set, print warnings
  65. Gl.title = ''        # Window title (default set later)
  66. Gl.name = 'mclock'    # Window title for resources
  67. Gl.border = 1        # If set, use a window border (and title)
  68. Gl.bg = 0, 0, 0        # Background color R, G, B value
  69. Gl.iconic = 0        # Set in iconic state
  70. Gl.fg = 255, 0, 0    # Alarm background RGB (either normal or alarm)
  71. Gl.ox,Gl.oy = 0,0    # Window origin
  72. Gl.cx,Gl.cy = 0,0    # Window size
  73. Gl.alarm_set = 0    # Alarm on or off
  74. Gl.alarm_on = 0        # Alarm is ringing
  75. Gl.alarm_time = 0    # Alarm time in seconds after midnight
  76. Gl.alarm_hours = 0    # Alarm hour setting, 24 hour clock
  77. Gl.alarm_minutes = 0    # Alarm minutes setting
  78. Gl.alarm_rgb = 0,0,0    # Alarm display RGB colors
  79. Gl.alarm_cmd = ''    # Command to execute when alarm goes off
  80. Gl.mouse2down = 0    # Mouse button state
  81. Gl.mouse3down = 0    # Mouse button state
  82. Gl.gong_cmd = ''    # Command to execute when chimes go off
  83. Gl.gong_int = 3600    # Gong interval
  84. Gl.indices = R, G, B    # Colors (permuted when alarm is on)
  85.  
  86. def main():
  87.     #
  88.     sys.stdout = sys.stderr        # All output is errors/warnings etc.
  89.     #
  90.     try:
  91.         args = getoptions()
  92.     except string.atoi_error, value:
  93.         usage(string.atoi_error, value)
  94.     except getopt.error, msg:
  95.         usage(getopt.error, msg)
  96.     #
  97.     if args:
  98.         realtime = 0
  99.         hours = string.atoi(args[0])
  100.         minutes = seconds = 0
  101.         if args[1:]: minutes = string.atoi(args[1])
  102.         if args[2:]: seconds = string.atoi(args[2])
  103.         localtime = ((hours*60)+minutes)*60+seconds
  104.     else:
  105.         realtime = 1
  106.     #
  107.     if Gl.title == '':
  108.         if realtime:
  109.             Gl.title = TITLE
  110.         else:
  111.             title = ''
  112.             for arg in args: title = title + ' ' + arg
  113.             Gl.title = title[1:]
  114.             del title
  115.     #
  116.     wid = makewindow()
  117.     Gl.ox,Gl.oy = getorigin()
  118.     Gl.cx,Gl.cy = getsize()
  119.     initmenu()
  120.     clearall()
  121.     #
  122.     if not Gl.update:
  123.         Gl.update = 60
  124.     #
  125.     if Gl.update <= 1:
  126.         Gl.timernoise = 6
  127.     else:
  128.         Gl.timernoise = 60
  129.     noise(TIMER0, Gl.timernoise)
  130.     #
  131.     qdevice(WINSHUT)
  132.     qdevice(WINQUIT)
  133.     qdevice(ESCKEY)
  134.     if realtime:
  135.         qdevice(TIMER0)
  136.     qdevice(REDRAW)
  137.     qdevice(WINFREEZE)
  138.     qdevice(WINTHAW)
  139.     qdevice(MENUBUTTON)    # MOUSE1
  140.     qdevice(MOUSE3)        # Left button
  141.     qdevice(MOUSE2)        # Middle button
  142.     unqdevice(INPUTCHANGE)
  143.     #
  144.     lasttime = 0
  145.     Gl.change = 1
  146.     while 1:
  147.         if realtime:
  148.             localtime = int(time.time() - Gl.tzdiff)
  149.         if Gl.alarm_set:
  150.             if localtime%(24*HOUR) == Gl.alarm_time:
  151.                 # Ring the alarm!
  152.                 if Gl.debug:
  153.                     print 'Rrrringg!'
  154.                 Gl.alarm_on = 1
  155.                 if Gl.alarm_cmd <> '':
  156.                     d = os.system(Gl.alarm_cmd+' '+`Gl.alarm_time/3600`+' '+`(Gl.alarm_time/60)%60` + ' &')
  157.                 Gl.change = 1
  158.                 clearall()
  159.         if Gl.alarm_on:
  160.             if (localtime - Gl.alarm_time) % (24*HOUR) > 300:
  161.                 # More than 5 minutes away from alarm
  162.                 Gl.alarm_on = 0
  163.                 if Gl.debug:
  164.                     print 'Alarm turned off'
  165.                 Gl.change = 1
  166.                 clearall()
  167.                 Gl.indices = R, G, B
  168.             else:
  169.                 if localtime % 2 == 0:
  170.                   # Permute color indices
  171.                   Gl.indices = Gl.indices[2:] + Gl.indices[:2]
  172.                   Gl.change = 1
  173.         if Gl.gong_cmd <> '' and localtime%Gl.gong_int == 0:
  174.             d = os.system(Gl.gong_cmd+' '+`(localtime/3600)%24`+' '+`(localtime/60)%60` + ' &')
  175.         if localtime/Gl.update <> lasttime/Gl.update:
  176.             if Gl.debug: print 'new time'
  177.             Gl.change = 1
  178.         if Gl.change:
  179.             if Gl.debug: print 'drawing'
  180.             doit(localtime)
  181.             lasttime = localtime
  182.             Gl.change = 0
  183.         dev, data = qread()
  184.         if Gl.debug and dev <> TIMER0:
  185.             print dev, data
  186.         if dev == TIMER0:
  187.             if Gl.debug > 1:
  188.                 print dev, data
  189.         elif dev == MOUSE3:
  190.             mousex = getvaluator(MOUSEX)
  191.             mousey = getvaluator(MOUSEY)
  192.             if mouseclick(3, data, mousex, mousey):
  193.                 Gl.change = 1
  194.         elif dev == MOUSE2:
  195.             mousex = getvaluator(MOUSEX)
  196.             mousey = getvaluator(MOUSEY)
  197.             if mouseclick(2, data, mousex, mousey):
  198.                 Gl.change = 1
  199.         elif dev == MOUSEX:
  200.             mousex = data
  201.             if Gl.mouse2down:
  202.                 mouse2track(mousex, mousey)
  203.             if Gl.mouse3down:
  204.                 mouse3track(mousex, mousey)
  205.         elif dev == MOUSEY:
  206.             mousey = data
  207.             if Gl.mouse2down:
  208.                 mouse2track(mousex, mousey)
  209.             if Gl.mouse3down:
  210.                 mouse3track(mousex, mousey)
  211.         elif dev == REDRAW or dev == REDRAWICONIC:
  212.             if Gl.debug:
  213.                 if dev == REDRAW: print 'REDRAW'
  214.                 else: print 'REDRAWICONIC'
  215.             reshapeviewport()
  216.             Gl.ox,Gl.oy = getorigin()
  217.             Gl.cx,Gl.cy = getsize()
  218.             Gl.change = 1
  219.             clearall()
  220.         elif dev == MENUBUTTON:
  221.             if Gl.debug: print 'MENUBUTTON'
  222.             handlemenu()
  223.         elif dev == WINFREEZE:
  224.             if Gl.debug: print 'WINFREEZE'
  225.             Gl.iconic = 1
  226.             noise(TIMER0, 60*60) # Redraw every 60 seconds only
  227.         elif dev == WINTHAW:
  228.             if Gl.debug: print 'WINTHAW'
  229.             Gl.iconic = 0
  230.             noise(TIMER0, Gl.timernoise)
  231.             Gl.change = 1
  232.         elif dev == ESCKEY or dev == WINSHUT or dev == WINQUIT:
  233.             if Gl.debug: print 'Exit'
  234.             sys.exit(0)
  235.  
  236. def getoptions():
  237.     optlist, args = getopt.getopt(sys.argv[1:], 'A:a:B:bc:dFfG:g:n:sT:t:u:wCMYK')
  238.     for optname, optarg in optlist:
  239.         if optname == '-A':
  240.             Gl.fg = eval(optarg)    # Should be (r,g,b)
  241.         elif optname == '-a':
  242.             Gl.alarm_cmd = optarg
  243.         elif optname == '-B':
  244.             Gl.bg = eval(optarg)    # Should be (r,g,b)
  245.         elif optname == '-b':
  246.             Gl.border = 0
  247.         elif optname == '-c':
  248.             Gl.colormap = string.atoi(optarg)
  249.         elif optname == '-d':
  250.             Gl.debug = Gl.debug + 1
  251.             Gl.warnings = 1
  252.         elif optname == '-F':
  253.             Gl.foreground = 1
  254.         elif optname == '-f':
  255.             Gl.fullscreen = 1
  256.         elif optname == '-G':
  257.             Gl.gong_int = 60*string.atoi(optarg)
  258.         elif optname == '-g':
  259.             Gl.gong_cmd = optarg
  260.         elif optname == '-n':
  261.             Gl.nparts = string.atoi(optarg)
  262.         elif optname == '-s':
  263.             Gl.doublebuffer = 0
  264.         elif optname == '-T':
  265.             Gl.title = Gl.name = optarg
  266.         elif optname == '-t':
  267.             Gl.tzdiff = string.atoi(optarg)
  268.         elif optname == '-u':
  269.             Gl.update = string.atoi(optarg)
  270.         elif optname == '-w':
  271.             Gl.warnings = 1
  272.         elif optname == '-C':
  273.             Gl.cyan = Gl.colorsubset = 1
  274.         elif optname == '-M':
  275.             Gl.magenta = Gl.colorsubset = 1
  276.         elif optname == '-Y':
  277.             Gl.yellow = Gl.colorsubset = 1
  278.         elif optname == '-K':
  279.             Gl.black = Gl.colorsubset = 1
  280.         else:
  281.             print 'Unsupported option', optname
  282.     return args
  283.  
  284. def usage(exc, msg):
  285.     if sys.argv:
  286.         progname = os.path.basename(sys.argv[0])
  287.     else:
  288.         progname = 'mclock'
  289.     #
  290.     print progname + ':',
  291.     if exc == string.atoi_error:
  292.         print 'non-numeric argument:',
  293.     print msg
  294.     #
  295.     print 'usage:', progname, '[options] [hh [mm [ss]]]'
  296.     #
  297.     print '-A r,g,b  : alarm background red,green,blue [255,0,0]'
  298.     print '-a cmd    : shell command executed when alarm goes off'
  299.     print '-B r,g,b  : background red,green,blue [0,0,0]'
  300.     print '            (-B SCREENBG uses the default screen background)'
  301.     print '-b        : suppress window border and title'
  302.     print '-c cmapid : select explicit colormap'
  303.     print '-d        : more debug output (implies -F, -w)'
  304.     print '-F        : run in foreground'
  305.     print '-f        : use full screen'
  306.     print '-G intrvl : interval between chimes in minutes [60]'
  307.     print '-g cmd    : shell command executed when chimes go off'
  308.     print '-s        : single buffer mode'
  309.     print '-w        : print various warnings'
  310.     print '-n nparts : number of parts [' + `NPARTS` + ']'
  311.     print '-T title  : alternate window title [\'' + TITLE + '\']'
  312.     print '-t tzdiff : time zone difference [' + `TZDIFF` + ']'
  313.     print '-u update : update interval [60]'
  314.     print '-CMYK     : Cyan, Magenta, Yellow or blacK overlay only'
  315.     print 'if hh [mm [ss]] is specified, display that time statically'
  316.     print 'on machines with < 12 bitplanes, -s is forced on'
  317.     #
  318.     sys.exit(2)
  319.  
  320. def doit(localtime):
  321.     hands = makehands(localtime)
  322.     list = makelist(hands)
  323.     render(list, hands)
  324.  
  325. def makehands(localtime):
  326.     localtime = localtime % (12*HOUR)
  327.     seconds_hand = MIDN + FULLC - (localtime*60) % FULLC
  328.     big_hand = (MIDN + FULLC - (localtime%HOUR)) % FULLC
  329.     little_hand = (MIDN + FULLC - ((localtime/12) % HOUR)) % FULLC
  330.     return little_hand, big_hand, seconds_hand
  331.  
  332. def makelist(hands):
  333.     little_hand, big_hand, seconds_hand = hands
  334.     total = []
  335.     if Gl.cyan or not Gl.colorsubset:
  336.         total = total + makesublist(big_hand, Gl.indices[0])
  337.     if Gl.magenta or not Gl.colorsubset:
  338.         total = total + makesublist(little_hand, Gl.indices[1])
  339.     if Gl.yellow or not Gl.colorsubset:
  340.         total = total + makesublist(MIDN, Gl.indices[2])
  341.     total.sort()
  342.     return total
  343.  
  344. def makesublist(first, icolor):
  345.     list = []
  346.     alpha = FULLC/Gl.nparts
  347.     a = first - alpha/2
  348.     for i in range(Gl.nparts):
  349.         angle = (a + i*alpha + FULLC) % FULLC
  350.         value = 255*(Gl.nparts-1-i)/(Gl.nparts-1)
  351.         list.append(angle, icolor, value)
  352.     list.sort()
  353.     a, icolor, value = list[0]
  354.     if a <> 0:
  355.         a, icolor, value = list[len(list)-1]
  356.         t = 0, icolor, value
  357.         list.insert(0, t)
  358.     return list
  359.  
  360. def rgb_fg():
  361.     return Gl.fg
  362.     # Obsolete code:
  363.     if Gl.alarm_on:
  364.         return Gl.bg
  365.     else:
  366.         return Gl.fg
  367.  
  368. def rgb_bg():
  369.     return Gl.bg
  370.     # Obsolete code:
  371.     if Gl.alarm_on:
  372.         return Gl.fg
  373.     else:
  374.         return Gl.bg
  375.  
  376. def clearall():
  377.     Gl.c3i(rgb_bg())
  378.     clear()
  379.     if Gl.doublebuffer:
  380.         swapbuffers()
  381.         clear()
  382.  
  383. def draw_alarm(color):
  384.     frontbuffer(TRUE)
  385.     Gl.c3i(color)
  386.     pushmatrix()
  387.     rotate(-((Gl.alarm_time/12)%3600), 'z')
  388.     bgnpolygon()
  389.     v2f( 0.00,1.00)
  390.     v2f( 0.04,1.05)
  391.     v2f(-0.04,1.05)
  392.     endpolygon()
  393.     popmatrix()
  394.     #
  395.     pushmatrix()
  396.     rotate(-((Gl.alarm_time)%3600), 'z')
  397.     bgnpolygon()
  398.     v2f( 0.00,1.05)
  399.     v2f( 0.07,1.10)
  400.     v2f(-0.07,1.10)
  401.     endpolygon()
  402.     popmatrix()
  403.     #
  404.     cmov2(-1.06, -1.06)
  405.     charstr(string.rjust(`Gl.alarm_time/3600`,2))
  406.     charstr(':')
  407.     charstr(string.zfill((Gl.alarm_time/60)%60,2))
  408.     frontbuffer(FALSE)
  409.  
  410. def render(list, (little_hand, big_hand, seconds_hand)):
  411.     #
  412.     if Gl.colormap:
  413.         resetindex()
  414.     #
  415.     if not list:
  416.         Gl.c3i((255, 255, 255)) # White
  417.         circf(0.0, 0.0, 1.0)
  418.     else:
  419.         list.append(3600, 0, 255) # Sentinel
  420.     #
  421.     rgb = [255, 255, 255]
  422.     a_prev = 0
  423.     for a, icolor, value in list:
  424.         if a <> a_prev:
  425.             [r, g, b] = rgb
  426.             if Gl.debug > 1:
  427.                 print rgb, a_prev, a
  428.             Gl.c3i((r, g, b))
  429.             arcf(0.0, 0.0, 1.0, a_prev, a)
  430.         rgb[icolor] = value
  431.         a_prev = a
  432.     #
  433.     if Gl.black or not Gl.colorsubset:
  434.         #
  435.         # Draw the hands -- in black
  436.         #
  437.         Gl.c3i((0, 0, 0))
  438.         #
  439.         if Gl.update == 1 and not Gl.iconic:
  440.             # Seconds hand is only drawn if we update every second
  441.             pushmatrix()
  442.             rotate(seconds_hand, 'z')
  443.             bgnline()
  444.             v2f(0.0, 0.0)
  445.             v2f(1.0, 0.0)
  446.             endline()
  447.             popmatrix()
  448.         #
  449.         pushmatrix()
  450.         rotate(big_hand, 'z')
  451.         rectf(0.0, -0.01, 0.97, 0.01)
  452.         circf(0.0, 0.0, 0.01)
  453.         circf(0.97, 0.0, 0.01)
  454.         popmatrix()
  455.         #
  456.         pushmatrix()
  457.         rotate(little_hand, 'z')
  458.         rectf(0.04, -0.02, 0.63, 0.02)
  459.         circf(0.04, 0.0, 0.02)
  460.         circf(0.63, 0.0, 0.02)
  461.         popmatrix()
  462.         #
  463.         # Draw the alarm time, if set or being set
  464.         #
  465.         if Gl.alarm_set:
  466.             draw_alarm(rgb_fg())
  467.     #
  468.     if Gl.doublebuffer: swapbuffers()
  469.  
  470. def makewindow():
  471.     #
  472.     if Gl.debug or Gl.foreground:
  473.         foreground()
  474.     #
  475.     if Gl.fullscreen:
  476.         scrwidth, scrheight = getgdesc(GD_XPMAX), getgdesc(GD_YPMAX)
  477.         prefposition(0, scrwidth-1, 0, scrheight-1)
  478.     else:
  479.         keepaspect(1, 1)
  480.         prefsize(80, 80)
  481.     #
  482.     if not Gl.border:
  483.         noborder()
  484.     wid = winopen(Gl.name)
  485.     wintitle(Gl.title)
  486.     #
  487.     if not Gl.fullscreen:
  488.         keepaspect(1, 1)
  489.         minsize(10, 10)
  490.         maxsize(2000, 2000)
  491.         iconsize(66, 66)
  492.         winconstraints()
  493.     #
  494.     nplanes = getplanes()
  495.     nmaps = getgdesc(GD_NMMAPS)
  496.     if Gl.warnings:
  497.         print nplanes, 'color planes,', nmaps, 'color maps'
  498.     #
  499.     if Gl.doublebuffer and not Gl.colormap and nplanes < 12:
  500.         if Gl.warnings: print 'forcing single buffer mode'
  501.         Gl.doublebuffer = 0
  502.     #
  503.     if Gl.colormap:
  504.         if not Gl.colormap:
  505.             Gl.colormap = nmaps - 1
  506.             if Gl.warnings:
  507.                 print 'not enough color planes available',
  508.                 print 'for RGB mode; forcing colormap mode'
  509.                 print 'using color map number', Gl.colormap
  510.         if not Gl.colorsubset:
  511.             needed = 3
  512.         else:
  513.             needed = Gl.cyan + Gl.magenta + Gl.yellow
  514.         needed = needed*Gl.nparts
  515.         if Gl.bg <> (0, 0, 0):
  516.             needed = needed+1
  517.         if Gl.fg <> (0, 0, 0):
  518.             needed = needed+1
  519.         if Gl.doublebuffer:
  520.             if needed > available(nplanes/2):
  521.                 Gl.doublebuffer = 0
  522.                 if Gl.warnings:
  523.                     print 'not enough colors available',
  524.                     print 'for double buffer mode;',
  525.                     print 'forcing single buffer mode'
  526.             else:
  527.                 nplanes = nplanes/2
  528.         if needed > available(nplanes):
  529.             # Do this warning always
  530.             print 'still not enough colors available;',
  531.             print 'parts will be left white'
  532.             print '(needed', needed, 'but have only',
  533.             print available(nplanes), 'colors available)'
  534.     #
  535.     if Gl.doublebuffer:
  536.         doublebuffer()
  537.         gconfig()
  538.     #
  539.     if Gl.colormap:
  540.         Gl.c3i = pseudo_c3i
  541.         fixcolormap()
  542.     else:
  543.         Gl.c3i = c3i
  544.         RGBmode()
  545.         gconfig()
  546.     #
  547.     if Gl.fullscreen:
  548.         # XXX Should find out true screen size using getgdesc()
  549.         ortho2(-1.1*1.280, 1.1*1.280, -1.1*1.024, 1.1*1.024)
  550.     else:
  551.         ortho2(-1.1, 1.1, -1.1, 1.1)
  552.     #
  553.     return wid
  554.  
  555. def available(nplanes):
  556.     return pow(2, nplanes) - 1    # Reserve one pixel for black
  557.  
  558. def fixcolormap():
  559.     multimap()
  560.     gconfig()
  561.     nplanes = getplanes()
  562.     if Gl.warnings:
  563.         print 'multimap mode has', nplanes, 'color planes'
  564.     imap = Gl.colormap
  565.     Gl.startindex = pow(2, nplanes) - 1
  566.     Gl.stopindex = 1
  567.     setmap(imap)
  568.     mapcolor(0, 0, 0, 0) # Fixed entry for black
  569.     if Gl.bg <> (0, 0, 0):
  570.         r, g, b = Gl.bg
  571.         mapcolor(1, r, g, b) # Fixed entry for Gl.bg
  572.         Gl.stopindex = 2
  573.     if Gl.fg <> (0, 0, 0):
  574.         r, g, b = Gl.fg
  575.         mapcolor(2, r, g, b) # Fixed entry for Gl.fg
  576.         Gl.stopindex = 3
  577.     Gl.overflow_seen = 0
  578.     resetindex()
  579.  
  580. def resetindex():
  581.     Gl.index = Gl.startindex
  582.  
  583. r0g0b0 = (0, 0, 0)
  584.  
  585. def pseudo_c3i(rgb):
  586.     if rgb == r0g0b0:
  587.         index = 0
  588.     elif rgb == Gl.bg:
  589.         index = 1
  590.     elif rgb == Gl.fg:
  591.         index = 2
  592.     else:
  593.         index = definecolor(rgb)
  594.     color(index)
  595.  
  596. def definecolor(rgb):
  597.     index = Gl.index
  598.     if index < Gl.stopindex:
  599.         if Gl.debug: print 'definecolor hard case', rgb
  600.         # First see if we already have this one...
  601.         for index in range(Gl.stopindex, Gl.startindex+1):
  602.             if rgb == getmcolor(index):
  603.                 if Gl.debug: print 'return', index
  604.                 return index
  605.         # Don't clobber reserverd colormap entries
  606.         if not Gl.overflow_seen:
  607.             # Shouldn't happen any more, hence no Gl.warnings test
  608.             print 'mclock: out of colormap entries'
  609.             Gl.overflow_seen = 1
  610.         return Gl.stopindex
  611.     r, g, b = rgb
  612.     if Gl.debug > 1: print 'mapcolor', (index, r, g, b)
  613.     mapcolor(index, r, g, b)
  614.     Gl.index = index - 1
  615.     return index
  616.  
  617. # Compute n**i
  618. def pow(n, i):
  619.     x = 1
  620.     for j in range(i): x = x*n
  621.     return x
  622.  
  623. def mouseclick(mouse, updown, x, y):
  624.     if updown == 1:
  625.         # mouse button came down, start tracking
  626.         if Gl.debug:
  627.             print 'mouse', mouse, 'down at', x, y
  628.         if mouse == 2:
  629.             Gl.mouse2down = 1
  630.             mouse2track(x, y)
  631.         elif mouse == 3:
  632.             Gl.mouse3down = 1
  633.             mouse3track(x, y)
  634.         else:
  635.             print 'fatal error'
  636.         qdevice(MOUSEX)
  637.         qdevice(MOUSEY)
  638.         return 0
  639.     else:
  640.         # mouse button came up, stop tracking
  641.         if Gl.debug:
  642.             print 'mouse', mouse, 'up at', x, y
  643.         unqdevice(MOUSEX)
  644.         unqdevice(MOUSEY)
  645.         if mouse == 2:
  646.             mouse2track(x, y)
  647.             Gl.mouse2down = 0
  648.         elif mouse == 3:
  649.             mouse3track(x, y)
  650.             Gl.mouse3down = 0
  651.         else:
  652.             print 'fatal error'
  653.         Gl.alarm_set = 1
  654.         return 1
  655.  
  656. def mouse3track(x, y):
  657.     # first compute polar coordinates from x and y
  658.     cx, cy = Gl.ox + Gl.cx/2, Gl.oy + Gl.cy/2
  659.     x, y = x - cx, y - cy
  660.     if (x, y) == (0, 0): return    # would cause an exception
  661.     minutes = int(30.5 + 30.0*math.atan2(float(-x), float(-y))/pi)
  662.     if minutes == 60: minutes = 0
  663.     a,b = Gl.alarm_minutes/15, minutes/15
  664.     if (a,b) == (0,3):
  665.         # Moved backward through 12 o'clock:
  666.         Gl.alarm_hours = Gl.alarm_hours - 1
  667.         if Gl.alarm_hours < 0: Gl.alarm_hours = Gl.alarm_hours + 24
  668.     if (a,b) == (3,0):
  669.         # Moved forward through 12 o'clock:
  670.         Gl.alarm_hours = Gl.alarm_hours + 1
  671.         if Gl.alarm_hours >= 24: Gl.alarm_hours = Gl.alarm_hours - 24
  672.     Gl.alarm_minutes = minutes
  673.     seconds = Gl.alarm_hours * HOUR + Gl.alarm_minutes * MINUTE
  674.     if seconds <> Gl.alarm_time:
  675.         draw_alarm(rgb_bg())
  676.         Gl.alarm_time = seconds
  677.         draw_alarm(rgb_fg())
  678.  
  679. def mouse2track(x, y):
  680.     # first compute polar coordinates from x and y
  681.     cx, cy = Gl.ox + Gl.cx/2, Gl.oy + Gl.cy/2
  682.     x, y = x - cx, y - cy
  683.     if (x, y) == (0, 0): return    # would cause an exception
  684.     hours = int(6.5 - float(Gl.alarm_minutes)/60.0 + 6.0*math.atan2(float(-x), float(-y))/pi)
  685.     if hours == 12: hours = 0
  686.     if (Gl.alarm_hours,hours) == (0,11):
  687.         # Moved backward through midnight:
  688.         Gl.alarm_hours = 23
  689.     elif (Gl.alarm_hours,hours) == (12,11):
  690.         # Moved backward through noon:
  691.         Gl.alarm_hours = 11
  692.     elif (Gl.alarm_hours,hours) == (11,0):
  693.         # Moved forward through noon:
  694.         Gl.alarm_hours = 12
  695.     elif (Gl.alarm_hours,hours) == (23,0):
  696.         # Moved forward through midnight:
  697.         Gl.alarm_hours = 0
  698.     elif Gl.alarm_hours < 12:
  699.         Gl.alarm_hours = hours
  700.     else:
  701.         Gl.alarm_hours = hours + 12
  702.     seconds = Gl.alarm_hours * HOUR + Gl.alarm_minutes * MINUTE
  703.     if seconds <> Gl.alarm_time:
  704.         draw_alarm(rgb_bg())
  705.         Gl.alarm_time = seconds
  706.         draw_alarm(rgb_fg())
  707.  
  708. def initmenu():
  709.     Gl.pup = pup = newpup()
  710.     addtopup(pup, 'M Clock%t|Alarm On/Off|Seconds Hand On/Off|Quit', 0)
  711.  
  712. def handlemenu():
  713.     item = dopup(Gl.pup)
  714.     if item == 1:
  715.         # Toggle alarm
  716.         if Gl.alarm_set:
  717.             Gl.alarm_set = 0
  718.             Gl.alarm_on = 0
  719.         else:
  720.             Gl.alarm_set = 1
  721.         Gl.change = 1
  722.         clearall()
  723.     elif item == 2:
  724.         # Toggle Seconds Hand
  725.         if Gl.update == 1:
  726.             Gl.update = 60
  727.             Gl.timernoise = 60
  728.         else:
  729.             Gl.update = 1
  730.             Gl.timernoise = 6
  731.         Gl.change = 1
  732.     elif item == 3:
  733.         if Gl.debug: print 'Exit'
  734.         sys.exit(0)
  735.  
  736. main()
  737.