This tutorial will show you how to create a simple ROX applet (a program that runs inside the panel). The applet will be a clock, so we'll also look at timed events.
You should have read the first tutorial.
It's good to be able to run applets in their own window too, and its very similar, so we'll start by creating a stand-alone clock application.
Create the application directory as before, and start with this code:
#!/usr/bin/env python import findrox; findrox.version(1, 9, 8) import rox from rox import g import time time_display = g.Label('') def update_time(): time_display.set_text(time.ctime()) update_time() main = rox.Window() main.add(time_display) main.show_all() rox.mainloop()
OK, that's pretty straighforward. A label in a window. To get the time to update we need to add a timeout. This takes the minimum time between calls (in ms) and a function to call. Add this just before entering the mainloop:
g.timeout_add(1000, update_time)
If you run this, you'll see that the time only updates once. update_time() needs to return True to get called again:
def update_time(): time_display.set_text(time.ctime()) return True
Copy AppRun as AppletRun. Instead of creating a rox.Window, create a rox.applet.Applet, passing the first command-line argument:
import sys from rox import applet main = applet.Applet(sys.argv[1])
Make sure AppletRun is executable. And that's it!
When you click on the program, it runs it in a window using AppRun, but if you drag it to a panel then ROX-Filer runs AppletRun with the ID of a socket on the panel.
For a more complicated task you would put most of the code in a separate file (eg main.py) and get AppRun and AppletRun to import that, to save duplicating code.
People often want to make applets that scale to the current size of the panel. The problems people often have with this are:
These are caused by the applet trying to tell the filer what size the applet wants to be. The filer then sets/limits the panel size as requested, which often causes the applet to try to change its size for the new panel, etc.
Here's how to do it correctly. This explanation assumes a horizontal panel. For vertical panels, reverse width and height...
The trick is: set your vertical size request to a small and fixed value. 8 is good. Set the horizontal width to the desired size.
The sequence then looks like this:
* Do not request the applet's actual height. This value is the minimum height for the applet. Stick to 8 (or whatever the actual minimum is).
* Do not request a height of -1. GTK will then use the widget's default natural size, which for images is the same situation as the previous point.
Here is a Demo Applet that both scales with the Panel and also adjusts to the orientation of the Panel (Horizontal or Vertical).
#!/usr/bin/env python import findrox findrox.version(1,9,0) import rox, sys from rox import applet, g # This XPM ripped EVILly from the GTK tutorials: xpm_data = [ "16 13 3 1", " c None", ". c #000000000000", "X c #FFFFFFFFFFFF", " ...... ", " .XXX.X. ", " .XXX.XX. ", " .XXX.XXX. ", " .XXX..... ", " .XXXXXXX. ", " .XXXXXXX. ", " .XXXXXXX. ", " .XXXXXXX. ", " .XXXXXXX. ", " .XXXXXXX. ", " .XXXXXXX. ", " ......... "] class DemoApplet(applet.Applet): """ A Demo Applet that displays a GtkImage and scales along with the Panel and adjusts according to the orientation of the Panel. """ def __init__(self): applet.Applet.__init__(self, sys.argv[1]) self.vertical = self.get_panel_orientation() in ('Left', 'Right') if self.vertical: self.set_size_request(8, -1) else: self.set_size_request(-1, 8) self.image = g.Image() self.add(self.image) self.pixbuf = g.gdk.pixbuf_new_from_xpm_data(xpm_data) self.image.set_from_pixbuf(self.pixbuf) self.size = 0 self.connect('size-allocate', self.event_callback) def event_callback(self, widget, rectangle): """ Get the new size and resize the pixbuf, but only if the size is different and is valid. This also assumes you want square widgets. """ side = self.get_panel_orientation() if self.vertical: size = rectangle[2] else: size = rectangle[3] if size != self.size: self.resize_image(size) def resize_image(self, size): """Create a scaled version of the pixmap, and set image to that.""" scaled_pixbuf = self.pixbuf.scale_simple(size, size, g.gdk.INTERP_BILINEAR) self.image.set_from_pixbuf(scaled_pixbuf) self.size = size def get_panel_orientation(self): "Return the panel orientation ('Top', 'Bottom', 'Left', 'Right')" pos = self.socket.property_get('_ROX_PANEL_MENU_POS', 'STRING', False) if pos: return pos[2].split(',')[0] return 'Bottom' main = DemoApplet() main.show_all() rox.mainloop()