#!/usr/bin/python # Import GNOME applet: import gnome.applet # Import Gtk+: import gtk import sys import os from string import * import gnome import gnome.ui # Constants TIME_TYPE = "time-type" TIME_DISABLE = "time-disable" ABOUT_TEXT = "xgrabber\nVersion: 0.9\nAuthor: Evan Hughes (ehughes@acm.org)\nWebpage: http://sourceforge.net/projects/xgrabber/" TOOLTIP_CONFIG_TYPE_WAIT = "Time to wait (in seconds) before disabling keyboard and mouse" TOOLTIP_CONFIG_DISABLE_WAIT = "Time to wait (in seconds) before enabling keyboard and mouse" class GrabbingWindow: """A window that grabs xserver focus, and doesn't give it back for a while. When the dismiss button is clicked, we hide ourselves and call our parent's cb. """ def __init__(self, grabbedText, predismissedText, time, cb): self.grabbedText = grabbedText self.predismissedText = predismissedText self.time = time self.callback = cb self.window = gtk.GtkWindow(gtk.WINDOW_TOPLEVEL) self.timerRunning = 0 # Create a box to stow all our bits and peices in box1 = gtk.GtkVBox(gtk.FALSE, 0) # Create the label full of text to show when predismissed self.textLabel = gtk.GtkLabel(self.predismissedText) self.textLabel.set_line_wrap(gtk.TRUE) predismissedLabelRequest = self.textLabel.size_request() # Create the label full of text to show when grabbing self.textLabel.set_text(self.grabbedText) grabbedLabelRequest = self.textLabel.size_request() # Set the label size, so we can handily switch self.textLabel.set_usize(max(predismissedLabelRequest[0], grabbedLabelRequest[0]), max(predismissedLabelRequest[1], grabbedLabelRequest[1])) box1.pack_start(self.textLabel, gtk.FALSE, gtk.FALSE, 3) self.textLabel.show() self.labelTimer = LabelTimer(self.time, self.timerExpired) box1.pack_start(self.labelTimer.getLabel(), gtk.FALSE, gtk.FALSE, 3) buttonLabel = gtk.GtkLabel("Dismiss") buttonLabel.show() self.doneButton = gtk.GtkButton() self.doneButton.connect("clicked", self.dismissButtonClicked, None) self.doneButton.add(buttonLabel) self.doneButton.show() box1.pack_start(self.doneButton, gtk.FALSE, gtk.FALSE, 0) box1.show() self.window.add_events(gtk.GDK.KEY_PRESS_MASK) # For mouse movements self.window.add_events(gtk.GDK.POINTER_MOTION_MASK) # For button presses self.window.add_events(gtk.GDK.BUTTON_PRESS_MASK) self.window.connect("motion_notify_event",self.deny) self.window.connect("key_press_event",self.deny) self.window.connect("button_press_event",self.deny) self.window.add(box1) # cb for something happening to the window. We don't like that, so we stop # it from propagating up def deny(self, event, *args): self.window.get_window().keyboard_grab(1, 0) self.window.get_window().pointer_grab(1, 0) return gtk.TRUE # Grab. def start(self): self.textLabel.set_text(self.grabbedText) self.doneButton.set_sensitive(gtk.FALSE) self.window.set_position(gtk.WIN_POS_CENTER) self.window.show() self.window.get_window().keyboard_grab(1, 0) self.window.get_window().pointer_grab(1, 0) self.labelTimer.start() self.timerRunning = 1; # cb for timer expiry def timerExpired(self): self.timerRunning = 0 self.textLabel.set_text(self.predismissedText) self.doneButton.set_sensitive(gtk.TRUE) self.doneButton.grab_focus() # cb for dismiss button being clicked def dismissButtonClicked(self, widget, data=None): self.window.get_window().keyboard_ungrab() self.window.get_window().pointer_ungrab() self.window.hide() self.callback() # get the the number of seconds remaining def getDefaultSecondsRemaining(self): return self.labelTimer.getDefaultSecondsRemaining() # Set the time left def setDefaultSecondsRemaining(self, value): self.labelTimer.setDefaultSecondsRemaining(value) class LabelTimer: """ A timer that counts down on an applet """ # time: How many seconds to wait # cb: The callback to call once the time has expired def __init__(self, time, cb): """ Set the default number of seconds to wait. Whenever the timer is restarted, we set our start value back to this. """ self.defaultSecondsRemaining = time """ Set the number of seconds we're going to wait for. """ self.secondsRemaining = 0 """ Set the callback we call once the time is up. """ self.callback = cb # Create a label to show be shown inside the applet: """ The label we're writing everything to """ self.label = gtk.GtkLabel(self.getTimeString()) # Set the font style = self.label.get_style().copy() style.font = gtk.load_font("-*-*-*-r-*-*-*-*-*-*-m-100-*-*") # Set the width self.label.set_style(style) self.label.set_usize(self.label.get_style().font.width("55555"), -1) # Show the label: self.label.show() # get the the number of seconds remaining def getDefaultSecondsRemaining(self): return self.defaultSecondsRemaining # Set the number of seconds remaining def setDefaultSecondsRemaining(self, value): oldDefault = self.defaultSecondsRemaining self.defaultSecondsRemaining = value # If we're running, set the seconds remaining to the new default less # the amount of used time. if (self.secondsRemaining > 0): self.secondsRemaining = value - (oldDefault - self.secondsRemaining) # Get the number of seconds remaining in a xx:xx form def getTimeString(self, time=-1): if time == -1: time = self.secondsRemaining minutes = time / 60 seconds = time % 60 # Make sure we have the correct number of zeros if (len(str(minutes)) == 1): minutes = "0" + str(minutes) if (len(str(seconds)) == 1): seconds = "0" + str(seconds) return str(minutes) + ":" + str(seconds) # The count-down timer def countdown(self): self.secondsRemaining = self.secondsRemaining - 1 self.showTimeRemaining() if (self.secondsRemaining <= 0): self.timerExpired() # Stop the timer return 0 return 1 # Shows the current time def showTimeRemaining(self): self.label.set_text(self.getTimeString()) # Called when we're done. def timerExpired(self): self.callback() # Called to start the timer def start(self): self.secondsRemaining = self.defaultSecondsRemaining self.showTimeRemaining() # Start our countdown timer gtk.timeout_add(1000, self.countdown) # Called to get our label widget def getLabel(self): return self.label class GrabberApplet: """The applet that does the grabbing. Starting point for everything else. """ def __init__(self): # Load the config file. values = {TIME_TYPE : 1800, TIME_DISABLE : 180} configFileName = os.path.expanduser("~/.xgrabber"); try: values = self.loadConfigFile(configFileName) except IOError, e: print "IOError on load: ", e self.saveConfigFile(configFileName, values) # Create an instance of the AppletWidget class: """ The applet we're running """ self.applet = gnome.applet.AppletWidget("xgrabber") """ The label that shows the time remaining on the applet """ self.labelTimer = LabelTimer(int(values[TIME_TYPE]), self.mainTimerExpired) """ The window that grabs for us """ self.grabWindow = GrabbingWindow("The focus has currently been grabbed. This window will remain displayed until the timer shown below completes. Clicking the button below dismisses this window and restarts the typing timer.", "Focus has been released. You may now return to typing.", int(values[TIME_DISABLE]), self.grabWindowExpired) # Create a frame: frame = gtk.GtkFrame() # Add the label to the frame: frame.add(self.labelTimer.getLabel()) # Show the frame: frame.show() # Add the frame to the applet: self.applet.add(frame) self.applet.register_stock_callback("name", gnome.ui.STOCK_MENU_PREF, "Preferences", self.preferencesMenu, 1) self.applet.register_stock_callback("about", gnome.ui.STOCK_MENU_ABOUT, "About xgrabber", self.aboutMenu, 1) # Show the applet self.applet.show() # Start the timer self.labelTimer.start() # cb for about menu def aboutMenu(self, *args): dialog = gnome.ui.GnomeDialog('About xgrabber', gnome.ui.STOCK_BUTTON_OK) label = gtk.GtkLabel() label.set_text(ABOUT_TEXT) label.set_justify(gtk.JUSTIFY_LEFT) label.show() dialog.vbox.pack_start(label) dialog.run_and_close() # cb for configuration menu def preferencesMenu(self, *args): dialog = gnome.ui.GnomeDialog('Preferences', gnome.ui.STOCK_BUTTON_OK, gnome.ui.STOCK_BUTTON_CANCEL) # Fill with field values fieldTable = gtk.GtkTable(2, 2, gtk.FALSE) # Create the type-wait pair typeWaitLabel = gtk.GtkLabel("Typing time") typeWaitLabel.show() fieldTable.attach(typeWaitLabel, 0, 1, 0, 1) typeWaitAdjustment = gtk.GtkAdjustment(self.labelTimer.getDefaultSecondsRemaining(), 0, 3600, 1, 60, 0) typeWaitSpinner = gtk.GtkSpinButton(typeWaitAdjustment, .5, 0) typeWaitSpinner.show() typeWaitTooltip = gtk.GtkTooltips() typeWaitTooltip.set_tip(typeWaitSpinner, TOOLTIP_CONFIG_TYPE_WAIT) fieldTable.attach(typeWaitSpinner, 1, 2, 0, 1) # Create the disable-wait pair disableWaitLabel = gtk.GtkLabel("Disable time") disableWaitLabel.show() fieldTable.attach(disableWaitLabel, 0, 1, 1, 2) disableWaitAdjustment = gtk.GtkAdjustment(self.grabWindow.getDefaultSecondsRemaining(), 0, 3600, 1, 60, 0) disableWaitSpinner = gtk.GtkSpinButton(disableWaitAdjustment, .5, 0) disableWaitSpinner.show() disableWaitTooltip = gtk.GtkTooltips() disableWaitTooltip.set_tip(disableWaitSpinner, TOOLTIP_CONFIG_DISABLE_WAIT) fieldTable.attach(disableWaitSpinner, 1, 2, 1, 2) fieldTable.show() dialog.vbox.pack_start(fieldTable) # was OK clicked? if (dialog.run_and_close() == 0): # Reset the typing timer self.labelTimer.setDefaultSecondsRemaining(typeWaitSpinner.get_value_as_int()) # Reset the disable timer self.grabWindow.setDefaultSecondsRemaining(disableWaitSpinner.get_value_as_int()) # Save the values values = {TIME_TYPE : typeWaitSpinner.get_value_as_int(), TIME_DISABLE : disableWaitSpinner.get_value_as_int()} configFileName = os.path.expanduser("~/.xgrabber"); self.saveConfigFile(configFileName, values) # load the configuration file def loadConfigFile(self, fileName): configFile = open(fileName) # Read the contents into a hash values = {} line = configFile.readline() while (line != ""): line = lstrip(rstrip(line)) (key, value) = split(line, "=", 1) values[key] = value line = configFile.readline() configFile.close() return values # Save the configuration file def saveConfigFile(self, fileName, values): configFile = open(fileName, "w") for key in values.keys(): configFile.write(str(key) + "=" + str(values[key]) + "\n") configFile.close() # cb to be triggered when our main timer is done def mainTimerExpired(self): # The main timer is done. Launch the grab window. self.grabWindow.start() # cb triggered when the grab window is done def grabWindowExpired(self): # Start the whole cycle over again self.labelTimer.start() # The main() function: def main(): GrabberApplet() # Get into the Gtk main-loop: gtk.mainloop() # This is plain old Python, so you should understand this: if __name__ == '__main__': main()