#!/usr/bin/python import gtk, gobject, cairo, wnck, math class Ball: def __init__ (self): self.window = gtk.Window() self.window.set_app_paintable(True) self.window.set_border_width(80) self.window.set_decorated(False) self.alpha_screen_changed(self.window) self.window.set_events(gtk.gdk.ALL_EVENTS_MASK) self.window.connect("button-press-event", self.button_press) self.window.connect("expose-event", self.expose) self.window.connect("focus-in-event", self.focus_in) self.moving = False # true when the ball is in motion and is NOT being dragged self.dragged = False # true when the ball is being dragged by the user self.x = 0 # x position self.y = 0 # y position self.width = 0 # width (used to check if we hit a wall) self.height = 0 # height (used to check if we hit a wall) self.vx = 0 # velocity along the x axis self.vy = 0 # velocity along the y axis self.gravity = 1.5 # gravity self.friction = 0.95 # friction along the bottom screen edge self.motion_time = 10 # time in milliseconds for motion timeout self.drag_time = 10 # time in milliseconds for drag timeout self.screen = wnck.screen_get_default() self.max_x = self.screen.get_width() self.max_y = self.screen.get_height() self.window.show_all() def move (self): """Timeout called when the ball is in motion.""" if not self.moving: print "Returning False... Stop moving." return False if self.y < self.max_y: self.vy += self.gravity self.x += self.vx # calculate new x position self.y += self.vy # calculate new y position print self.vy,self.y+self.height, self.max_y # right screen edge if self.x + self.width > self.max_x: self.vx *= -0.8 self.x = self.max_x - self.width # left screen edge elif self.x < 0: self.vx *= -0.8 self.x = 0 # bottom screen edge if self.y + self.height > self.max_y: self.vy *= -0.8 self.y = self.max_y - self.height # top screen edge elif self.y < 0: self.vy *= -0.8 self.y = 0 # if the x velocity is too small just make it 0 if abs(self.vx) < 1: self.vx = 0 # if the y velocity is too small just make it 0 if abs(self.vy) < 1: self.vy = 0 # if there's no movement in any direction stop moving if self.y + self.height == self.max_y and self.vy == 0: self.vx *= self.friction if self.vx == 0: self.moving = False # the timeout will automatically cancel itself # finally, move self.window.move(int(self.x), int(self.y)) # move to the new location return True def update_speed (self): """Timeout called when the ball is being dragged.""" # handle change in x direction pass # gtk handlers def button_press (self, widget, event): print "button press event" # drag the window if event.button == 1: self.moving = False # stop bouncing (the timeout will automatically cancel itself) self.dragged = True self.begin_x, self.begin_y = self.window.get_position() self.begin_time_x = self.begin_time_y = gobject.get_current_time() self.window.begin_move_drag(event.button, int(event.x_root), int(event.y_root), event.time) self.update_speed_timeout = gobject.timeout_add(self.drag_time, self.update_speed) def expose (self, widget, event): print "expose event" self.width = widget.allocation.width self.height = widget.allocation.height ctx = widget.window.cairo_create() ctx.save() ctx.set_source_rgba(1, 1, 1, 0) ctx.set_operator (cairo.OPERATOR_SOURCE) ctx.paint() ctx.restore() ctx.save() ctx.arc(self.width/2, self.height/2, min(self.height, self.width)/2, 0, 2*math.pi) #color = gtk.gdk.color_parse("red") #ctx.set_source_rgba(color.red, color.green, color.blue, 0.8) pattern = cairo.LinearGradient(0.0, 0.0, 0.0, self.height) pattern.add_color_stop_rgb(1.0, 1.0, 1.0, 1.0) pattern.add_color_stop_rgb(0.0, 0.0, 0.0, 0.0) ctx.set_source(pattern) ctx.fill() ctx.restore def focus_in (self, widget, event): """Callback for focus event. This gets called when a drag ends.""" if self.dragged: # set attributes self.dragged = False self.moving = True # get the current time and position now = gobject.get_current_time() self.x, self.y = self.window.get_position() # calculate the velocity along the x and y axis self.vx = (self.x - self.begin_x) / ((now - self.begin_time_x) * 100) self.vy = (self.y - self.begin_y) / ((now - self.begin_time_y) * 100) # start the timeout function self.move_timeout = gobject.timeout_add(self.motion_time, self.move) def alpha_screen_changed (self, widget, screen=None): """set colormap for window""" if screen is None: screen = widget.get_screen() map = screen.get_rgba_colormap() if map is None: map = screen.get_rgb_colormap() widget.set_colormap(map) if __name__ == "__main__": app = Ball() gtk.main()