Tuesday, June 19, 2007

Public Key

You can find my key on the public servers. I specifically post it to hkp://keys.gnupg.net.

pub 4096R/77292AC1 2009-02-23 Eric Polino (aluink)
Key fingerprint = E516 191C 79D1 C904 CF5C B45A E9D3 1121 7729 2AC1

Friday, June 15, 2007

Sound

Finch now has sound. It took me only a couple hours to get it in too! Before you do thinking I'm some big genius for doing it so fast, just wait a minute. Sound works pretty much the same way as Pidgin sound works, or at least it should since I copied that code over. I know, I know copying code is one of the seven deadly since of coding. Let me talk about that for a bit.

As it stands, sound is directly in Finch. This isn't the optimal solution since many folk don't want sound in their console application. This is because remoting into a box and having sound go off can be rather unsettling for the parties in the same room as the serving machine. So as it stands the sound is directly in Finch, but will most likely be moved later to either a plugin or something to make it an optional feature. One could argue that all a user has to do is disable sound when they are remoting in, but that can get dicey and an unneeded extra the user has to worry about. This would diverge from the simple model which Pidgin tries to achieve. So a plugin sounds likely.

We are discussing options for how to deal with this on the mailing list right now. I'll provide an update later when a decision is reached.

Tuesday, June 12, 2007

New Projects

Sorry for having been quiet in the last few days. I've been busy here at home and haven't been working as hard as I was last week. The well here at home is having some issues, so we haven't had water the last two days and won't have any tomorrow. In any case, here are some bits of information on a few things I've been doing and a little info on what is to come.

The other developers have put a lot of work into building workspaces. I haven't had time to look at it yet, but I'm assuming that it's like having multiple desktops in a graphical environment. So they did lots of work on that and had merged all their work into the upcoming release branch. So I propagated those changes into my branch. That was a lot of work since there were many conflicts to resolve. Thanks to the help of meld, it wasn't too bad. The default conflict resolution tool is Vim and I'm glad I didn't use that. I might figure it out sometime later because I'm a Vim addict, but for now, I'm glad I had a nice graphical tool to do it with.

I have also received permission to create a few sub-branches to my branch. See I don't have commit access to the entire MTN tree. I'm only allowed to commit to my branch, im.pidgin.soc.2007.finchfeat. So I asked if I could create three sub-branches, .sound, .logging, and .bindings, so that I can work on the other parts of my project separate from eachother. In the end I will merge those changes together of course, but in the mean time if I get one working, those change can be pulled into another branch to be incorporated into a release without having to worry about the changes in the other projects affecting anything. When I start doing the little things I was hoping to do, I will either create another sub-branch for that or just do it in .finchfeat directly. I'll cross that bridge when I get to it.

So there is a little update on some work. I hope to start working on .sound in the next few days. I've already begun to do some research and think I know where I'm going with it. Having a good foundation on how things works already is allowing me to work faster now. A great feeling!!!

Friday, June 8, 2007

Object Orientation in C

If you ask a common programmer to list a few languages that are object oriented they will most likely list ones like, Java, SmallTalk, C++, Ruby, and so forth. You won't hear people say that C is an OO language, because it isn't. This doesn't mean it doesn't have the capability of doing it though. Working with libgnt, the console based graphical library Finch uses, I am using a lot of OO design built in C. I'd like to give just a short intro to how it all works because I think it's rather neat.

Classes are defined with structs. Thus all the member variables are simply put into a struct and methods that operate on a class are function pointers in a struct. Because C doesn't have a native concept of OO, if a class were declared with both member variables and member functions defined in the same struct, a waste of memory would ensue. Every time an instance of a class would be created, those pointers would be created again. So a separation of static members and instance members much be created. This can be done in many ways, but a common convention and the one used by libgnt is to create another struct called ${CLASSNAME}Class. This struct would contain all the function pointers for the given class, and would also hold any static variables.

The following is a simple example of a circle class that stores some basic circle information and a few methods that operate on circles.

/*circle.h*/

#ifndef __circle_h__
#define __circle_h__

typedef struct _Circle Circle;
typedef struct _CircleClass CircleClass;

struct _Circle {
float radius;
};

struct _CircleClass {
float pi;
void (*draw) (Circle * c);
float (*get_circumference) (Circle * c);

void (*set_radius) (Circle *c,float r);
float (*get_radius) (Circle *c);

Circle * (*new) (float r, int c);
void (*destroy) (Circle *);
};

CircleClass * get_circle_class();

#endif

#include "circle.h"

#include
#include

static void circle_draw(Circle * c){
/* Do the drawing here */
printf("Drawing a circle with radius %f\n",c->radius);
}

static float circle_get_circumference(Circle * c){
return get_circle_class()->pi * c->radius * 2.00;
}

static void circle_set_radius(Circle *c, float r){
c->radius = r;
}
static float circle_get_radius(Circle *c){
return c->radius;
}
static Circle * circle_new(float r, int color){
Circle *c = (Circle *)malloc(sizeof(Circle));
c->radius = r;
return c;
}

static void circle_destroy(Circle *c){
if(c){
free(c);
}
}

/********************
* Exported Methods *
********************/

CircleClass * get_circle_class(){
static CircleClass * klass = NULL;

if(klass == NULL){
klass = (CircleClass *)malloc(sizeof(CircleClass));
klass->draw = circle_draw;
klass->get_circumference = circle_get_circumference;
klass->get_radius = circle_get_radius;
klass->set_radius = circle_set_radius;
klass->new = circle_new;
klass->destroy = circle_destroy;

klass->pi = 3.14;
}
return klass;
}

/*client.c*/

#include
#include "circle.h"

int main(){

CircleClass * klass= get_circle_class();
Circle * c = klass->new(2.45,6);

float circum = klass->get_circumference(c);
float radius = klass->get_radius(c);

printf("Circle Data\n\tCircumference: %f\n\tRadius: %f\n",circum,radius);

klass->draw(c);

klass->destroy(c);

return 0;
}

Object orientation wouldn't be worth much without some inheritance. So let's see how that's done. It's actually very simple. The first member of the struct is the parent struct. So if you cast an object to it's parent-type, you have a pointer to it's first member, and parent class instance. Isn't that just neat! The following shows how to add a Shape parent class to Circle.

/*shape.h*/

#ifndef __shape_h__
#define __shape_h__

typedef struct _Shape Shape;
typedef struct _ShapeClass ShapeClass;

struct _Shape {
int color;
int border;
};

struct _ShapeClass {
void (*set_color) (Shape *c, int color);
int (*get_color) (Shape *c);

void (*set_border) (Shape *c, int border);
int (*get_border) (Shape *c);
};

void * shape_class_init(ShapeClass *sc);

#endif

/*shape.c*/

#include "shape.h"


static void shape_get_border(Shape *s){
return r->border;
}
static void shape_set_border(Shape *s, int border){
s->border = border;
}

static void shape_set_color(Shape *s, int color){
s->color = color;
}
static int shape_get_color(Shape *s){
return s->color;
}

/********************
* Exported Methods *
********************/

void * shape_class_init(ShapeClass *sc ){
ShapeClass *sc = ShapeClass *)malloc(sizeof(ShapeClass));

sc->get_color = shape_get_color;
sc->set_color = shape_set_color;

sc->set_border = shape_set_border;
c->get_border = shape_get_border;
}
And a few changes to the first few files.
/*circle.h*/

#include "shape.h"

struct _Circle{
Shape parent;
/* other members */
};

struct _CircleClass {
ShapeClass parent;
/* other members */
Circle * (*new) (float r, int color, int border);
};

/*circle.c*/
static Circle * circle_new(float r, int color, int border){
Circle *c = (Circle *)malloc(sizeof(Circle));
Shape *s = (Shape *)c;
c->radius = r;
s->color = color;
s->border = border;
return c;
}

CircleClass * get_circle_class(){
static CircleClass * klass = NULL;
ShapeClass *sc;

if(klass == NULL){
klass = (CircleClass *)malloc(sizeof(CircleClass));
klass->draw = circle_draw;
klass->get_circumference = circle_get_circumference;
klass->get_radius = circle_get_radius;
klass->set_radius = circle_set_radius;
klass->new = circle_new;
klass->destroy = circle_destroy;

sc = (ShapeClass*)klass;
/* override anything here */
klass->pi = 3.14;
}
return klass;
}

So there you can see how things are inherited. A simple cast gets you the parent object. There should only be one instance of CircleClass and it should contain a unique instance of ShapeClass that will be shared among all circles.

This demonstration was very rough and dirty and probably has a few problems since I wrote it up pretty fast and had a baby to deal with while I was piecing it all together, but I'm sure the basic concept makes sense. With the help of GLib and its object instantiation framework this design works a lot better. GLib gives you abstract classes, interfaces and much more, but things are still all in C.

This probably isn't the recommended way of doing OO, but the point is that C can do it. Hope this was informative and it has encourages you to dig a little deeper. If this is case, I recommend you read this paper on OO in C.

Wednesday, June 6, 2007

Key Reassignment Done

After many hours of research and coding I finally got the key reassignment capabilities in. Though it turned out to be a simpler task than I had expected, it still had its own series of bumps and surprises along the way.

The first and obvious bump was for me to become familiar enough with how things work to be able to utilize and modify the current code to make it do what I want it to do. But like I said above, this was one of the simpler things in the end. The association of keys to actions is setup like this. Every GntWidget is a GntBindable. GntBindable is associated with GntBindableClass. GntBindableClass contains three hash tables. The first we won't bother talking about here, but the other two are of interest to us.

The first table contains (name,Action) key/value pairs. The names are strings like "gained-focus", "window-moved", "key-pressed", etc. The Actions are the the functions performed. The second table contains (key,ActionParam). The keys are simply strings that represent keystrokes entered by the user. Then the ActionParam contain an action and parameters that are passed to that action.

So now when a key is pressed, the associated ActionParam is looked up from the related hash table and it is executed, simple as that. Sure there are some tricky things to happen along the way as far as what gets to execute the action, the window manager, a window, or a widget inside that window, but that's beyond the scope of this post. Maybe someday when I have nothing to write about, I'll post some more information on that.

Now that you have a basic understanding of how actions are performed based on keystrokes, I can tell you how assigning new key combinations to actions is done. When the user types alt-/ or alt-\ for widget or window manager reassignments, respectively, a list of available actions are displayed. From there a user scrolls to the desired action and hits . The needed information is given to a new window. This information being, ActionName, original key combination, and the GntBindable being modified; keep in mind that the window manager is a GntBindable also. From there we can get the GntBindableClass. The user then types in a new keystroke and selects the Bind button.

To replace a key assignment, two reassignments need to be done. First we reassign the old keystrokes to activate a NULL action. The reassignment function treats this as a delete action and deletes the (oldKeys, ActionParam) entry in the table. Then a second call to the same function is made with the new key combination. From the name, an Action is retrieved from the (name,Action) hash table. An ActionParam is created by associating this action with the parameters passed in. At this point, no actions make use of parameters, so this process will have to be modified slightly later to pass along needed parameters. Then it simply puts an entry in the (key, ActionParam) table with the new keys and the new ActionParam.

Sure one could argue that a function that takes two key combinations could change the key from the old to the new combinations. But since this is done very seldom, there isn't much of a need for this function. Maybe someday, it will be added.

So there you have it, this is how key reassignment is done. Feel free to ask some questions if certain parts are unclear. I will give some updates in a while, since this process still has some refining to do, such as some windows have special keystrokes they handle.

Tuesday, June 5, 2007

Payment #1

This year Google has decided to pay us via Western Union (WU). I guess last year they were sending checks and doing wire transfers. They were having issues with a lot of the wire transfers and in some countries the checks would take weeks to clear. So they spent a lot of time this year looking for a better solution. This solution was to pay most of us with WU and to setup wire transfers for the rest of the student where WU wasn't a viable option for their country. So, needless to say, being in the US I am one of the students getting paid with WU.

The fun all started when I went to get my payment the first time. It was Monday evening. I went down to the local WU agent at the Rite Aid. So I had all the information and identification I needed with me. I had a bad feeling things were going to go sour when I told them I was there to receive. They asked me how much, so I told them $500. They immediately had this look like they weren't sure they had enough, but they checked things out and had enough. So now they tried to run it through and it wanted a phone number. I told them I didn't need one, but she persisted that she couldn't run it without. Somewhat annoyed I told her I'd go home and write to get a number. Well, I didn't need a number; she even tried it without after I left and it worked. I'll refrain from calling her names, but that really ticked me off that she did that. So when I came back the next day to tell her that I didn't have the number and to try it without, she then told me that I didn't need it. So I had wasted a whole day, remember I don't have a car, so I have to wait for Holly to come home with the car to run down there. So any delays in the evening and I have to wait another whole day.

Moving on to the second hurdle, my information was entered wrong by the sender. Yes, Google is capable of making mistakes. They had entered my city as Newport, Nebraska instead of Newport, New Hampshire. WU wouldn't let the payment go through cause I was in the wrong district. When I wrote Google about it, it took 6 hrs to get a reply...they learned quickly what didn't work. I guess there were a lot of mistakes on the first batch. All the sender had to do was call WU and have my address changed. For some reason I was told my payment would be ready on Friday. Not sure if that was because they would send my updated information along with the second batch or what, but that was the case. So I had to wait till Friday to get it.

Come Friday I went back to Rite Aid to try again. This was my 5th trip there, I was about done with any type of screwing around. This time I couldn't get paid cause they didn't have $500 to give me, mistake #2 by Rite Aid. WU pays by check, you can cash that check wherever you want. I didn't know that at the time. So I agreed and left. It was already late and I didn't want to head out to the next town to go to the other WU agent out there. So I had to wait till Sunday now.

Finally on Sunday, I went to the other town, found the other agent, and got paid. This was when I found out it was just a check and I could have gotten paid on Friday. I was happy enough to get cash in my hands that I wasn't able to be upset. But looking back on it now, I'm just ticked at the fact that Rite Aid wasted 3 days for me. The first time they wasted a day cause I could have tried it then to find out that my address was wrong. The second time they wasted two days, cause I could have gotten paid on Friday, but instead had to wait till Sunday. I HATE HAVING MY TIME WASTED!!

So there you have it, my story of how I got my first pay from Google Summer of Code. You can find proof with this receipt.

Monday, June 4, 2007

Label Issues

I spent a good deal of time yesterday trying to figure out why a simple piece of code wouldn't work. I was working on the key binding stuff again. The way I want it to work is for the rebinding window to display the key combination caught to the user. When the window is first drawn it displays a label that contains 'KEY:""' (the single quote are for the reader and the double quotes actually appear in the label). Then when the user types in a combination it should update to 'KEY:"comb"', where comb is a human readable representation of the key combination entered by the user. Well, it's a pretty easy setup, you have a key_pressed listener that gets the label as an argument. A quick lookup to convert the keys received to a nicer format. Then a quick update to the label text and it should work nicely.

After several hours of staring at the code, quite a bit of research into the underlying code. I simply couldn't figure out why the label wouldn't update. I tried printing the keys out to stderr but something weird was happening there too. When I printed out the ASCII values one at a time, they came out nicely, as I would expect. But when I tried printing them out as a string, it printed blank. Well, come to find out, the problems with fprintf and label updating weren't related, they just happened to yield the same result. When we tried a quick test by executing printf("%s\n","\033" "a"), the equivalent to Alt-a, only a newline would print. So it was just a nuance of printf behavior. The issue with the label was different.

I spoke with my mentor for about an hour about this issue and finally he decided to pull the code and have a look for himself. He was taking too long, so at about 0030 I went to bed. He wrote back at 0200 saying he figured out what was wrong. It seems that when gnt_label_draw() was being called, it would first set an INVISIBLE flag, but failed to unset it before returning. It was a quick fix that required a lot of digging. So he fixed it and pushed it upstream. This morning I did a pull and merged his changes into mine and it worked.

Now we have issues with the label not redrawing nicely. But at least it's redrawing now. So I get to continue hacking away at this project.

Friday, June 1, 2007

Key Reassignment

So the first part of my project this summer is to work into Finch the ability to (re)bind keys to actions. So far I haven't done much productive work because I'm still learning how the API works. As it stands now, I have built a window that flows from a window listing the actions available to the current widget and the key bindings associated with those actions.


When I started working, the window listing the key assignments and their associated actions was already created. The user was able to hit a key combination (Alt-/) and it would come up showing a listing for the widget currently in focus. The user was able to scroll up and down the list, but it was merely informational. I took this and added the ability to hit on a given keystroke/actions pair. Pressing on a pair triggers the creation of a new window that prompts the user to type in a new key combination to be bound to the action. It's a pretty simple concept, one that most who have dealt with modifying shortcuts for a window manager have seen before.

The hard part I'm still trying to figure out is how to gather all the needed information I'll need when the rebinding call occurs. I need the following information: key combination, the class object for the widget, callback function for the action, name for the action, and an optional list of parameters to pass to the callback function. The key combination is trivial, I grab it from the user and store it. The class of the widget I can get from the parent window that listed all the keystroke/action pairs. The callback function is tricky, I haven't figured out how to do that yet. The name of the action I can get from the keystroke/action listing window. The parameters I really don't know what to do here. I'm not even sure if any of the actions take parameters at this point. I get the feeling this is just a feature that is available but not being used yet. So I'll have to talk to Sadrul, my mentor.

So as can be seen, all the information I need for the reassignment is available at the start of this process. My only task is to gather it, grab a new key combination from the user and call a register_action method. Depending on how things are implemented, I might have to check to see if another action is bound to that key combination to prevent double assignments. This is another thing I'll have to talk to my mentor about.

I can't wait to get to a point where I can commit my code and have the other developers tell me what is good and what needs to change. I am often stressed about not knowing whether a way of doing something is bad and/or not liked by the Pidgin development team. On the other hand this is causing me to really think about how I do things. So that in the end, if they don't like something I did, I can at least have something to stand on and defend my method. This could possibly even bring a new concept to the team, thus offer change and benefit.