Tuesday, August 31, 2010

Using Cairo with Gtkmm

Okay we should be all familiar with the Cairo API. If this is the first time you've ever heard of Cairo outside of a reference to Egypt then let me give you a quick peek at Cairo.



Cairo is pretty much the main library used for drawing anything with vectors. It is used everywhere, sort of like SQLite. The website is http://cairographics.org/



In the GNOME trifecta of things, Cairo provides the 2D drawing API, whereas Pango provides the Text Rendering API, and Gtk-Glib provide the toolkit/glue for all the above.



The neat thing about Cairo is that output is not limited to the screen. Backends for Cairo can be written for anything, so things drawn in Cairo can be outputted to an SVG file, OpenGL commands, a printer, or to a Pixbuf for use in a very popular web browser (Firefox anyone).



So today I'm going to use Cairomm (C++ bindings for Cairo) to do some basic drawing. Here is our header file justin_draw.h that defines our DrawingArea.



#ifndef SAMPLE04_JUSTIN
#define SAMPLE04_JUSTIN

#include <gtkmm/drawingarea.h>

class JustinDraw : public Gtk::DrawingArea
{

public:
JustinDraw();
virtual ~JustinDraw();

protected:
virtual bool on_expose_event(GdkEventExpose* event);

};

#endif



The only thing of note here is that we are going to define an on_expose_event. This is important because this is the method that is called when the window needs to draw itself. Either because the Window is new, or we've uncovered the window an exposed a part of it that was under another window.




Now let's implement our Gtk::DrawingArea with our justin_draw.cc file:



#include "justin_draw.h"
#include <cairomm/context.h>

JustinDraw::JustinDraw() {}

JustinDraw::~JustinDraw() {}

bool JustinDraw::on_expose_event(GdkEventExpose* event)
{
Glib::RefPtr<Gdk::Window> window = get_window();

if (window)
{
Gtk::Allocation a = get_allocation();
const int w = a.get_width();
const int h = a.get_height();

int xc, yc;
xc = w/2;
yc = h/2;

Cairo::RefPtr<Cairo::Context> cr = window->create_cairo_context();
cr->set_line_width(10.0);

cr->rectangle(event->area.x, event->area.y, event->area.width, event->area.height);
cr->clip();

cr->set_source_rgb(0.8, 0.0, 0.0);
cr->move_to(0,0);
cr->line_to(xc,yc);
cr->line_to(0,h);
cr->move_to(xc,yc);
cr->line_to(w,yc);
cr->stroke();
}

return true;
}



Notice a couple of things here before we move on. Drawing an entire screen with Cairo should be done very rarely. Not to say Cairo is slow but there is no need to waste time on drawing. The cr->rectangle(...); cr->clip(); parts allow us to focus on only the part of the window that has changed. Pretty much all code that uses Cairo has something similar to this so it's a good idea to include something like this in you code before you actually do any drawing.




Also notice that we are using a Cairo::RefPtr. Yes Cairo has it's own type of RefPtr's that you must use to hold Cairo related things. You have no idea how much time you can waste using the wrong type of RefPtr.




Finally, our program that uses our new Gtk::DrawingArea. main.cc

#include "justin_draw.h"
#include <gtkmm/main.h>
#include <gtkmm/window.h>

int main(int argc, char** argv)
{
Gtk::Main kit(argc, argv);

Gtk::Window win;
win.set_title("DrawingArea");

JustinDraw area;
win.add(area);
area.show();

Gtk::Main::run(win);

return 0;
}



And that's all there is to it! You can hit up basically any manual on Cairo to find all the 2D API commands. It's basically a 1:1 translation between the C and C++ bindings so you shouldn't have any problems there.




Tomorrow I'm going to cover Making a throbbing image in Java, because I'm gotten two emails over the last four days asking how to do that. Till then, Cheers!

Sunday, August 29, 2010

Trying out L2TPv3 in Linux 2.6.35.4

So I built me a 2.6.35.4 kernel to try out the new L2TPv3 support offered in this kernel.

L2TPv3 is pretty good and the newest kernel provides awesome RFC 3931 support, but I would advise some people to stick with L2TPv2. Not a lot of 3rd party vendors are there yet and the newest version has a lot of overhead over the wire.

I'm still on the fence about btrfs. I'll give it another six months before I actually change my LVM over.

Oh and by the by. The new kernel improves LVM response by about 5% - 10% depending on setup.

Friday, August 13, 2010

I hate Jennifer Aniston.

This is f'ing funny.


Jennifer Aniston Adopts 33-Year-Old Boyfriend From Africa

Wednesday, August 04, 2010

A Quick try of Gtkmm

Okay I figure I would give my hand a try at some Gtkmm. The API is pretty much like most curses and Java Windowing framework. So let's do a quick sample.

Let's start with our header file for the Window, we'll call it window1.h


#ifndef WINDOW_1_DEF_H
#define WINDOW_1_DEF_H

#include<gtkmm/window.h>
#include<gtkmm/button.h>
#include<gtkmm/entry.h>
#include<gtkmm/box.h>

class Window1 : public Gtk::Window {

public:

Window1();
virtual ~Window1();

protected:

void on_button1_clicked();

private:

Gtk::Button button1, button2;
Gtk::Entry entry1;
Gtk::VBox vbox1;

};

#endif



All of that should explain itself. Basically the object is a Gtk::Window, which is the top level container (widget, whatever you want to call it). We are adding two Gtk::Button, a Gtk::Entry (text entry widget), and a Gtk::VBox which is the layout container.

Now the fun thing about Gtkmm is that you don't have to "new" objects into existence. Instead Gtkmm will handle the memory allocation for you in most cases!! However, if you need to dynamically allocate objects or you need them outside of the class scope then your own your own, unless you use the Gtkmm smart pointer Glib::RefPtr<>, which is basically the same as the std::auto_ptr<> for those of you who have studied standard C++.

Okay let's implement the window, this will be in most logically window1.cc


#include "window1.h"
#include <iostream>
#include<gtkmm/main.h>

Window1::Window1() : button1("Print"), button2("Ouit") {

set_size_request(200,100);
set_title("Text Entry Demo");

add(vbox1);

entry1.set_max_length(25);
entry1.set_text("Enter something");
entry1.select_region(0,entry1.get_text_length());

vbox1.add(entry1);

button1.signal_clicked().connect(sigc::mem_fun(*this,&Window1::on_button1_clicked));
button2.signal_clicked().connect(sigc::ptr_fun(&Gtk::Main::quit));

vbox1.add(button1);
vbox1.add(button2);

show_all();
}

Window1::~Window1() {
using namespace std;
cout << "Say goodbye" << endl;
}

void Window1::on_button1_clicked() {
std::cout << "You have entered: " << entry1.get_text() << std::endl;
}



Okay this one has a couple of things to cover. Like what the heck is the sigc namespace?!

sigc is the library that Gtkmm uses to implement callbacks. A callback is a function or method that is called from another function. Basically the on_click method of your buttons gets called when you click on them. The method basically says, when I'm clicked run ________(insert blank line)________. The callback fills in the blank line.

Now historically there is basically one way to do this in C, but in C++ there must be at least a dozen libraries that do this. I won't get into why this is because that's a much bigger topic.

At anyrate, sigc is the tool that Gtkmm has chosen to implement callbacks. sigc has two ways to add callbacks. mem_fun and ptr_fun, both used here. mem_fun, allows you to call a method and ptr_fun allows you to call a function. Pretty clear cut there. As you can see I've connected the button2's click to the Gtk::Main::quit, which of course does what it says. Quits.

The other button, button1, I've connected to the on_button1_clicked method. This method simply uses standard C++ cout to write information to standard out. You may notice that I use the entry1.get_text() method within the on_button1_clicked() method and that I don't cast it's result to std::string. That's the neatest part of Gtkmm is that it was made to work with the C++ STL so well. Gtkmm already implements the logic needed to cast Glib::ustring (which is what the get_text() wethod returns) to std::string.

The rest of the code is pretty simple to follow.

So now that we have implemented our window we need an application that actually uses it.

I present main.cc


#include<gtkmm/main.h>
#include"window1.h"

int main(int argc, char *argv[]){

Gtk::Main kit(argc, argv);
Window1 w;
Gtk::Main::run(w);

return 0;
}



This is as basic as you can make an application that uses our window.

The results are here.


Clicking on the Print button outputs the text box on standard out and clicking quit, well quits. As you can see Gtkmm is very much like most other Toolkits, semantics are a little different here and there and you'll use some of the core tools of Gtkmm a little differently but overall you'll easily see how Gtkmm compares to things like SWT, Swing, and QT.

And since I said something about QT, it's worth saying something about it. If you have ever used QT then you know about it's signal/slot system and moc. Well Gtkmm takes the "high road" on this one and uses sigc to implement callbacks in a C++ standard-ish kind of way. The downfall of this, however, is that every callback must be statically typed. This amounts to a lot of double work. If you implement a signal connection in Glade, you must also implement that connection in Gtkmm by importing the widget and then using sigc.

I know this is one of the downfalls of C++'s strong type safety system and name mangling system. QT gets around this with moc but then using moc makes your code non-C++ standard compliant, which I don't think anybody really has a problem with except the people behind Gtkmm.

At anyrate, at risk for getting way off topic, Gtkmm is a neat little wrapper around Gtk+ and you should give it a whirl. You'll be making Gtk+ applications in no time, and best of all is the Gtkmm library works on Windows, Mac, Linux, BSD, and other Unix systems.
Link to Gtkmm

Tuesday, August 03, 2010

Is it just me?

Does it seem that Colbie Caillat has incredibly "wide" eyes? Is that even a thing? Maybe, I'm just mental?



Oh her song on the radio is a nifty little tune, and she was on the the Next Food Network Star show too. Before that I would have sworn that you were talking about a type of cheese.