Gtk2::Gdk
- On Screen Clock To display text on screen, we will normally use a Gtk2::Label
. This does not allow us to have a transparent background. If we want to display text with a transparent background, it becomes more involved. We have to dig deeper and use some of the Gtk2::Gdk
classes to accomplish our goal.
Table 10-5. Gtk2 object classes used
Gtk2 Class Name |
---|
Gtk2::Window |
Gtk2::VBox |
Gtk2::EventBox |
Gtk2::Image |
Gtk2::DrawingArea |
Gtk2::Style |
Gtk2::Pango |
Table 10-6. Gtk2::Gdk
object classes used
Gtk2::Gdk Class Name |
---|
Gtk2::Gdk::Pixmap |
Gtk2::Gdk::Pixbuf |
Gtk2::Gdk::Colormap |
Gtk2::Gdk::Window |
Gtk2::Gdk::Drawable |
Gtk2::Gdk::Event |
In the tables above there are classes new to us. This section will briefly list each one plus their use in our application.
Gtk2::Style
: Almost every displayable Gtk2
widget has a style associated to it. You can modify or use certain methods from a widget's associated style class.
Gtk2::Pango
: This is used especially for internationalization purposes. It also allows you to modify how text will be presented on screen
Gtk2::DrawingArea
: We will use this as a simple canvas to draw pango text upon. It can also be used to draw lines, dots, colors etc upon.
Gtk2::Gdk::Pixbuf
: This is like the word says, a buffer of pixels. These pixels can be sourced from various places, the Gtk2::Gdk::Pixbuf
is used on the X client where the Gtk2::Gdk::Pixmap
is used on the X server. The pixels can be modified.(read image manipulation) We can change certain colors to a alpha channel. Scaling is also possible.
Gtk2::Gdk::Colormap
: Colormaps are used to store the mappings between the RGB values you ask for and the actual, hardware-dependent values used to display those colors. We will use the default system colormap.
Gtk2::Gdk::Drawable
: This class allows you to use the Gtk2::DrawingArea
and the Gtk2::Gdk::Pixmap
as a canvas, by supplying various drawing methods. Both of them are subclasses of Gtk2::Gdk::Drawable
The program will be implemented as follows:
We create a Gtk2::Window
of type "popup", add a Gtk2::VBox
to it.
We create a Gtk2::EventBox
and add a Gtk2::Image
to it, then we add it to the Gtk2::VBox
and make them all visible.
Now we create a Gtk2::DrawingArea
and, since it does not have any size, we have to allocate quite a large size to it, to make sure we do not run out of space when we draw upon it. This is added the Gtk2::VBox
but only realized, and not shown, since we will only use it as a workspace.
We also implement a timeout that will run a sub every second.
We fetch the local Gtk2::Gdk::Colormap
from the system, and we create a pango layout from the Gtk2::DrawingArea
.
We will now look what the sub that gets called every second does.
We fetch the text that needs to be displayed. In our sample, we get the local time, and we format it using the pango markup language. This is added to the created pango layout.
Get the size of the newly formatted pango layout.
Create a Gtk2::Gdk::Pixmap
the size of this pixmap, draw the pango onto the Gtk2::Gdk::Pixmap
.
Create a Gtk2::Gdk::Pixbuf
and fetch the text from the Gtk2::Gdk::Drawable
. Mask out the background to an alpha channel.
Project this Gtk2::Gdk::Pixbuf
with transparent background onto a Gtk2::Image
.
Change the shape of the Gtk2::Window
.
The program can be found here: 'OSD Clock'
1 #!/usr/bin/perl -w 2 3 use strict; 4 use Glib qw/TRUE FALSE/; 5 use Gtk2 '-init'; 6 7 #add a timer to run each second 8 Glib::Timeout->add (1000,\&new_screen); 9 10 #create a popup window -> this allow us to modify its shape to 11 #that of a Gtk::Gdk::Pixmap class. 12 my $window= Gtk2::Window->new('popup'); 13 14 15 #standard packing widget 16 my $vbox = Gtk2::VBox->new(FALSE,0); 17 18 my $eventbox = Gtk2::EventBox->new(); 19 $window->signal_connect('button-press-event' => sub{ exit(0);}); 20 #create an image containing nothing, this will be set each time 21 #the &new_screen sub runs 22 my $img = Gtk2::Image->new_from_pixmap (undef, undef); 23 24 $eventbox->add($img); 25 26 $vbox->pack_start($eventbox,FALSE,FALSE,0); 27 28 $window->add($vbox); 29 30 $window->set_position('center-always'); 31 #show all BEFORE we add $drawing_area - we do not want to show the drawing 32 #area, we only use it as a working surface. 33 $window->show_all(); 34 35 #Create a drawing area, and set is big enough to hold the maximum size our 36 #text will ever be. 37 my $drawing_area = Gtk2::DrawingArea->new; 38 $drawing_area->set_size_request (1600, 1600); 39 $vbox->pack_start($drawing_area,FALSE,FALSE,0); 40 41 #realize it, since it will not be displayed, but we need to 42 #get hold of the Gdk classes that needs it to be either shown, 43 #or realized 44 $drawing_area->realize; 45 #create a new pango layout for this drawing area 46 #this is a method from the Gtk2::Widged class 47 my $pango_layout = $drawing_area->create_pango_layout(""); 48 #get the defalt colormap (will be needed later on) 49 my $colormap = Gtk2::Gdk::Colormap->get_system; 50 #initial paint of screen 51 &new_screen; 52 53 Gtk2->main; 54 55 sub new_screen { 56 57 #this sub will get a new value of text, and display it on the screen in a shaped 58 #window, to get there needs a few steps 59 60 #get the text that we want to display on the screen. 61 my $ts = ret_time(); 62 63 #Set our pango layout, to reflect the text and format that we want. 64 #NOTE We deliberately set the background to a certain color to convert 65 #that color to a alpha channel, that will give us the "clear" background. 66 $pango_layout->set_markup("<span background = '#000000' foreground = '#FF0000' size = '20000' weight ='heavy'>Exact time:\n</span><span background = '#000000' foreground= '#00FF00' size='30000' weight = 'ultralight'><i><u>$ts</u></i></span>"); 67 68 #Get the size of this layout after the text was set. 69 my($pango_w,$pango_h)=$pango_layout->get_pixel_size; 70 71 #Now we have the size, we can create a pixmap that will be the 72 #'Gtk2::Gdk::Drawable' that we will draw upon 73 my $pixmap = Gtk2::Gdk::Pixmap->new ($drawing_area->window, 74 $pango_w, 75 $pango_h, 76 -1); 77 #Draw a black block on $pixmap the size of the pango text. 78 #This allow us to use newlines in the pango text, just make sure the pango 79 #background is also black, as to convert all the black to a alpha channel 80 $pixmap->draw_rectangle ($drawing_area->style->black_gc, 81 TRUE, 82 0, 0, 83 $pango_w, 84 $pango_h); 85 86 #draw the pango layout on the drawable. 87 $pixmap->draw_layout($drawing_area->style->white_gc,0,0,$pango_layout); 88 89 #create a Gtk2::Gdk::Pixbuf that we will use to grab the pango text from the 90 #drawable (Gtk2::Gdk::Pixmap which is a Gtk2::Gdk::Drawable) 91 my $pixbuf = Gtk2::Gdk::Pixbuf->new ('rgb', TRUE, 8, $pango_w, $pango_h); 92 93 #here we get create a pixbuff from the drawable, this is where we need the colormap 94 $pixbuf->get_from_drawable ($pixmap, $colormap, 0, 0, 0,0, $pango_w, $pango_h); 95 96 #Remove the background (we use the color we specified as the pango text's 97 #background 98 $pixbuf = $pixbuf->add_alpha (TRUE, 0, 0 , 0); 99 100 #create a pixmap and mask from the Gtk2::Gdk::Pixbuf 101 my ($pm, $m) = $pixbuf->render_pixmap_and_mask (255); 102 #shrink our window to make sure the mask and pixmap will be on the same spot. 103 $window->resize(4,4); 104 #replace the old $img with the new pixmap and mask 105 $img->set_from_pixmap ($pm, $m); 106 107 #shape our window accordingly 108 $window->shape_combine_mask ($m, 0, 0); 109 110 return TRUE; 111 112 } 113 114 115 sub ret_time { 116 #sub to return a string containing the time 117 my($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst)= localtime(time+3600); 118 my @lst =("Sun","Mon","Tue","Wed","Thu","Fri","Sat"); 119 my $thisday =$lst[$wday]; 120 $year = $year + 1900; 121 122 ($sec =~ m/\d{2}/)||($sec = "0".$sec); 123 ($min =~ m/\d{2}/)||($min = "0".$min); 124 ($hour =~ m/\d{2}/)||($hour = "0".$hour); 125 $mon = $mon +1; 126 #print("\n"); 127 my $ts = "$thisday $mday/$mon/$year $hour:$min:$sec"; 128 129 return $ts; 130 } 131