Monday, 28 December 2009

To Cloud, or not to Cloud? That is the Question.

To Cloud or not to Cloud?

For a lot of geeks, this is a question that is preying on their minds. I am one of those geeks.

I'm fairly well integrated into the Cloud already; my fate was cemented when I bought a Google Phone. "What? You mean I can access all my mail and contacts and stuff from my phone and if I change it on my phone it will change my Google Contacts too? And my calendar and everything? I'M IN!" There are obvious benefits to having your phone info synced with the Cloud, like, never EVER again having to spend an entire evening alone with a bottle of wine and a DVD, manually inputting every single one of your contacts on your new phone...But if we take another step further, beyond phone contacts, calendars, etc., we start looking at things like personal documents, photos, videos and (potentially) application settings like for Firefox.

There are already choices out there to use...Google Docs was one of the first I heard about, Ubuntu One is a new Ubuntu service that is now standard with the latest release, and only just today, Dropbox was featured on Dork Adore (one of my favourite geek-centric blogs).

So it's easy to get into Cloud computing if you're of a mind to, but I still can't help feeling a bit uneasy about the whole thing. I don't know if it's my general mistrust of large organisations (I still feel a little niggly that Google has all my personal details in a file, regardless of what their privacy policy is), or whether it's influence from old Libertarian friends or my ex-military parents. I'm just not sure whether I would feel comfortable leaving someone else in charge of my documents.

Of course, there are a few big advantages to holding more information in the Cloud. For instance, I'm willing to bet that Google has a much more regimented and regular backing-up process than I have! And given that you could put almost all of your files now into a Cloud folder, it makes it easier to run small, lightweight computers like netbooks, because the only files you'd have to keep actually ON your computer would be your system files.

For me, at the moment, I'm undecided. I suspect, with all things, when it becomes a practical necessity to share more of my files with other computers, I will probably give it a go. But for now, I'll give it a miss, and just stick to syncing my contacts and calendar.

Monday, 21 December 2009

GTK Theming Isn't Really That Hard. Honest!

So, I've been away for awhile...

Been rebuilding a machine, getting fed up, buying a new computer, setting that up, and generally being ADHD with all my little projects...

Anyway, I've started working on GTK themes, and as it turns out, it's not as difficult as it seems at first. I've released two GTK themes recently on my DeviantArt account...Have a look!
From Screenshots
Ultrasuede is the first of the two themes, named after the sofa I sit on to do most of my work! I'm not entirely sure why I started with this one, after all, it's no secret that it's difficult to write dark GTK themes, and as it turns out, it's even harder when you want only parts of the theme to be dark (in this case, the menubar/menus and toolbar). I still consider this one a work-in-progress, but I still love it for its softness of colour and general readability. Plus, it's got lovely blue tooltips!

From Screenshots
Venus is my latest theme, and the one I'm currently using. I originally started it because I wanted to write a grey/silver theme, but the ones I find tend to be either too simple or too shiny. I don't like my widgets to be glassy; I prefer a more soft, smooth lighting effect. So I started with the colour scheme from elementary (one of my favourite packages, although like I said, I find the widgets too shiny) and went from there...Changing the accent colour from blue to green, and added soft yellow tooltips. Very soothing, I think!

But anyway, the point of this post was not to toot my own horn ("Too late!" I hear you cry...), it was to explain how I started in GTK theming, and point out some tips to get you started doing it for yourself.

First things first: Step 1 is to grab some GTK themes that you like. Some of my favourites are:
Then, find and bookmark the GTK Hierarchy and the GTK reference manual. All of these things will help you later.

Now, close your eyes, hold your breath, and jump in.

Start by copying one of your themes into ~/.themes/ and changing the folder to something you can remember. I tend to use ~/.themes/Untitled for new themes I'm working on. The file structure of a GTK theme looks like:
~/
+-- .themes/
    +-- Untitled/
        +-- gtk-2.0/
            +-- gtkrc
If it's a theme like Human, you may also find folders for Metacity, an index.theme (for icons) and others inside the Untitled/ folder.

It's the gtkrc that we want to edit. It's a simple text file with a relatively simple layout.

First, you may define a colour scheme (this is what turns up in the Colors tab of the Customize... dialog in Gnome Appearance Preferences). It will look something like this:
gtk_color_scheme = "base_color:#F7F9FA\nfg_color:#4D4D4D\ntooltip_fg_color:#000000\nselected_bg_color:#a5b26b\nselected_fg_color:#ffffff\ntext_color:#4D4D4D\nbg_color:#D6D6D6\ntooltip_bg_color:#f2f29d"
Next, you should have a listing of styles, in the format
style "name"
{
    Various style properties
}
Start with a "default" style, which will be applied to all widgets, and then on to more specific styles that will apply to only certain widgets. The default style can contain as much as little as you like, but typically you will find:
  • Some specific widget style properties, of the format GtkWidget::style-property = value
  • Thickness parameters, which define the padding of the objects inside widgets, and look line xthickness = value and ythickness = value
  • Colour definitions, of which there should be 20: foreground (fg), background (bg), background of entry fields (base) and text (text), and five states for each (normal, prelight, active, selected and insensitive)
  • Default settings for the engine (if any) you choose to use
The "default" style for my latest theme, Venus, looks like this:
style "default"
{
 GtkButton ::child-displacement-x  = 1
 GtkButton ::child-displacement-y  = 1
 GtkButton ::default-border  = { 0, 0, 0, 0 }

 GtkPaned ::handle-size   = 6

 GtkRange ::trough-border   = 0
 GtkRange ::slider-width   = 13
 GtkRange ::stepper-size   = 13
 GtkRange ::stepper-spacing  = 1
 GtkRange ::activate-slider  = 1
 GtkRange ::arrow-displacement-x  = 1
 GtkRange ::arrow-displacement-y  = 1
 GtkRange ::arrow-scaling   = 0.7

  GtkScale ::slider-width  = 13 # Needs to be ODD in order to center evenly
  GtkScale ::slider-length  = 13
  GtkScale ::trough-side-details = 1 # 0 = empty slider, 1 = filled
  GtkScale ::trough-border  = 1

  GtkScrollbar ::min-slider-length = 42

 GtkScrolledWindow ::scrollbar-spacing = 3

 GtkNotebook ::tab-curvature   = 1
 GtkNotebook ::tab-overlap   = 1

 GtkMenuBar ::internal-padding  = 0

 GtkExpander ::expander-size   = 14

 GtkToolbar ::internal-padding  = 0
 GtkToolButton ::icon-spacing   = 3

 GtkTreeView ::expander-size   = 14
 GtkTreeView ::vertical-separator  = 0

 GtkMenu  ::horizontal-padding  = 0
 GtkMenu  ::vertical-padding  = 0

 xthickness = 1
 ythickness = 1

 fg[NORMAL]        = @fg_color
 fg[PRELIGHT]      = @fg_color
 fg[SELECTED]      = @selected_fg_color
 fg[ACTIVE]        = @fg_color
 fg[INSENSITIVE]   = shade (0.7, @bg_color)

 bg[NORMAL]        = @bg_color
 bg[PRELIGHT]      = shade (1.05, @bg_color)
 bg[SELECTED]   = @selected_bg_color
 bg[INSENSITIVE]   = @bg_color
 bg[ACTIVE]        = shade (0.95, @bg_color)

 base[NORMAL]      = @base_color
 base[PRELIGHT]    = shade (0.95, @bg_color)
 base[ACTIVE]      = shade (0.7, @bg_color) # Unfocused selected text background
 base[SELECTED]    = @selected_bg_color
 base[INSENSITIVE] = @bg_color

 text[NORMAL]      = @text_color
 text[PRELIGHT]    = @text_color
 text[ACTIVE]      = @selected_fg_color
 text[SELECTED]    = @selected_fg_color
 text[INSENSITIVE] = shade (0.7, @bg_color)

 engine "murrine" 
 {
  animation  = TRUE # FALSE = disabled, TRUE = enabled
  colorize_scrollbar = TRUE # FALSE = disabled, TRUE = enabled
  scrollbar_color  = @selected_bg_color
  contrast  = 0.8 # 0.8 for less contrast, more than 1.0 for more contrast on borders
  glazestyle  = 0  # 0 = flat highlight, 1 = curved highlight, 2 = concave style, 3 = top curved highlight, 4 = beryl highlight
  gradient_shades  = {1.05,1.02,1.02,1.0} # default: {1.1,1.0,1.0,1.1}
  gradients  = TRUE # FALSE = disabled, TRUE = enabled
  highlight_shade  = 1.0 # set highlight amount for buttons or widgets
  lightborder_shade = 1.0 # sets lightborder amount for buttons or widgets
  lightborderstyle = 0   # 0 = lightborder on top side, 1 = lightborder on all sides
  listviewheaderstyle = 1   # 0 = flat, 1 = glassy, 2 = raised
  listviewstyle  = 1   # 0 = nothing, 1 = dotted
  menubaritemstyle = 1   # 0 = menuitem look, 1 = button look
  menubarstyle  = 0   # 0 = flat, 1 = glassy, 2 = gradient, 3 = striped
  menuitemstyle  = 1  # 0 = flat, 1 = glassy, 2 = striped
  menustyle  = 0   # 0 = no vertical menu stripe, 1 = display vertical menu stripe
  reliefstyle  = 1   # 0 = flat, 1 = inset, 2 = shadow
  rgba   = FALSE # FALSE = disabled, TRUE = enabled
  roundness  = 3  # 0 = squared, 1 = old default, more will increase roundness
  scrollbarstyle  = 0     # 0 = nothing, 1 = circles, 2 = handles, 3 = diagonal stripes, 4 = diagonal stripes and handles, 5 = horizontal stripes, 6 = horizontal stripes and handles
  sliderstyle  = 0  # 0 = nothing added, 1 = handles
  stepperstyle  = 1  # 0 = standard, 1 = integrated stepper handles, 2 = unknown
  toolbarstyle  = 2  # 0 = flat, 1 = glassy, 2 = gradient
 }
}
Since you will apply the default style to all widgets and then pick out individual widgets to change after that, the other styles you define will typically only be a couple of lines long, which will override the corresponding lines from the default style.

After you've defined all your styles, then comes widget matching. It's how the theme applies your styles to all the various widgets that might pop up in GTK-based programs. There are three types of matching:
  1. Class
  2. Widget class
  3. Widget
The first (class) is the most generic, and the last (widget) is most specific. Widget overrides widget class overrides class. Within each type of matching, later lines override earlier lines. So for instance:
class "GtkWidget" style "default"
widget_class "*GtkCombo*" style "wider"
widget "*.gtk-combobox-popup-menu.*" style "combobox-popup"
Here, all widgets first have the default theme applied. Then anything whose widget class contains GtkCombo (note the * wild card) has the "wider" style applied. Finally, the very specific case of a widget with .gtk-combobox-popup-menu. will have "combobox-popup" applied. (Please note there is some trickiness here to do with the wild card * -- you can also use $ for a single-character wild card -- and the best place to learn to navigate it is to use trial and error.)

And that's it...For the basics, that is! To get started making your own theme, I would start by tweaking with someone else's, so you get a feel for what changes what. Then if you get really brave, you can start from scratch (which after a few goes, I actually found was easiest!).

The hardest parts of GTK theming are the widget matching, understanding how the widgets are arranged in a hierarchy and understanding how their styles get inherited. I can't say I'm an expert, but that's where step 1 comes in! The best way to learn is a combination of looking at other people's themes and reading the GTK documentation. The latter is particularly useful because the widget hierarchy pages have listings of what style-properties you can specify in your styles.

I hope this gives some of you out there the courage to go ahead and try it...As with all things open-source, the more of us out there doing it, the easier it makes it for all of us!

Saturday, 14 November 2009

Desktop Customisation: A Double-Edged Sword

I can safely say that I am a desktop customisation addict.

The problem is, I'm not entirely sure that it's because I actually enjoy it, or whether it's because I am completely OCD and just perpetually in pursuit of pixel-perfection.

It's fair to say that one of the things I love most about working with Linux (and the open-source community in general) is the extent to which you can customise everything to your liking. And I do mean EVERYTHING. (I think my favourite obscure thing to customise has got to be the spacing between the menu and submenus in Openbox...Awesome!) HOWEVER, if you're a little perfectionistic like yours truly, it can also be the bane of your existence, because after a while, you start to notice every pixel out of place. Or how many times have you downloaded a new GTK theme, only to find that, for instance, the Google search box on your Firefox toolbar ends up being the wrong colour for some unknown reason?

The sad fact of it is that because Linux distributions are largely written and edited by the Linux community, many of whom do their coding in their spare time in front of the telly, there is rarely the attention to detail in GUI design as there is in a commercial OS like Mac OS or Windows. I hate to admit it, but while those desktop environments only give you a few choices of looks, overall, those choices are much cleaner and more complete. Linux distros tend to be easier to customise (in fact, they usually encourage it by installing several default themes), but the overall impact is weaker because they tend to be standalone themes, rather than part of a whole desktop "look". Add to this the awkwardness of GTK vs. Qt, incompatibilities with Firefox, quirks of various panels and window managers and, well, you can get a bit of a mess. So really, desktop customisation is a bit of a double-edged sword: whilst you can tweak your GUI to your heart's content, more often than not, I find that each tweak uncovers something else needing to be tweaked, and it quickly becomes a downward spiral...

Thursday, 5 November 2009

Memory usage with imlib2 for Lua

I recently started working with imlib2 bindings for Lua as part of the work I'm doing with learning the whole Cairo thing...Please see my latest post over on the Conky Blog.

However, I ran into an interesting problem when I was writing that script, not having written anything with imlib2 bindings before! As I was testing my photo album script, I found that I had a memory leak...The longer I left my script to run, the more and more my memory usage would ramp up until it topped out and I found I couldn't display any more photos. Eep! Not really what you want from a photo album.

So I thought I'd share with you a little bit about how imlib2 draws pictures, as opposed to the way Cairo does it, because having had a bit of experience with Cairo actually led me to think about image drawing in a way that made it difficult to work with imlib2, because the two are so different.

First of all, why use imlib2 at all when you can, to some extent, use Cairo to draw pictures? Well, the reason I turned my hand to it was because I wanted to be able to render .jpg images in my Conky, and the Cairo bindings we use can only interpret .png at the moment, through cairo_image_surface_create_from_png(...). By contrast, if you load an image using imlib2, it auto-detects the type and scans its own internal libraries to find a suitable decoder. So imlib2 has a much broader range of image type support, with no fiddling.

If you want to manipulate existing images in imlib2, first you need to load the image into memory with imlib_load_image(...). Eventually, if you want to then draw that image onto the Conky window, you'll use the imlib_render_image_on_drawable(...) function. However, if you want to manipulate that image first, you will need to do all your manipulation on a "buffer" image before you render it onto the surface.

Now, I'm not very good (yet!) at working with transformations in Cairo, so I'm used to thinking of things like a plotter...Move to (a, b), draw a line to (x, y) and stroke. So when I want to draw an image to a window, what I really want to do is load an image, select the rectangle to draw it into, and then "fill" it in...But that's not really the way to do it with imlib2. My example will be my photo album script...Essentially, I wanted to load an image and draw it onto the Conky window at a set (smaller) size. However, I found that if I just load the image and then draw the image at a smaller size using the following:
imlib_blend_image_onto_image(image, 0, 0, 0, w_img, h_img, 0, 0, width, height)
imlib_render_image_on_drawable(xc - width/2, yc - height/2)
I wound up with a horrific memory leak...Basically, I was loading the images into memory and LEAVING THEM THERE. AT FULL SIZE. Ouch.

(For those of you who are wondering, the lines above shrink the image from w_img x h_img down to a specified width x height, then draw it on the Conky window at the coordinates in the second line...)

What you need to do to avoid the memory leak is to very carefully manage your memory usage by freeing your images after you're done with them. The good way, then, to draw my reduced images onto the Conky window is to use the following method:
image = imlib_load_image(album_dir .. filename)
if image == nil then return end
imlib_context_set_image(image)

w_img, h_img = imlib_image_get_width(), imlib_image_get_height()
buffer = imlib_create_image(width, height)
imlib_context_set_image(buffer)

imlib_blend_image_onto_image(image, 0, 0, 0, w_img, h_img, 0, 0, width, height)
imlib_context_set_image(image)
imlib_free_image()

imlib_context_set_image(buffer)
imlib_render_image_on_drawable(xc - width/2, yc - height/2)
imlib_free_image()
This code does the following:
  1. loads the given image into memory, in a variable called "image"
  2. checks to see if the image has loaded successfully; if not, breaks out of the function
  3. sets the imlib2 context to be "image"
  4. grabs the dimensions of the loaded image
  5. creates a "buffer" image
  6. sets the context to be "buffer", so we can blend onto it
  7. draws a scaled-down version of the image onto "buffer"
  8. sets the context back to "image", so we can release it
  9. releases the original loaded image, so we are then just left with the scaled down version, still held in memory
  10. sets the context back to "buffer", so we can draw what's on it onto the drawable window
  11. draws whatever's in "buffer" onto the Conky window
  12. releases the buffer image
You can start to see from this how you can also use the buffer image (or a series of them!) to do some fairly sophisticated image & text manipulation before rendering onto the drawable window.

For more information on the functions available to you in imlib2, check out their documentation.

In the meantime, here, have a screenie :)
From Screenshots
You can also grab the script that made it, from the Conky Blog, or my DevArt account.

Thursday, 29 October 2009

Slowly moving to DeviantArt

Well, after searching long and hard for somewhere that would host all of my scripts, etc., I have finally settled on DeviantArt. I have moved away from gnome-look.org because (a) I don't actually use Gnome anymore, so it seems a little silly to ringfence myself in that way, (b) gnome-look.org doesn't allow me to upload full-size screenies, which means I have to resize everything before uploading (read: what a pain!) and (c) ooooh, aren't the colours on the DevArt website purty?

So anyway, you can see my new profile here, and as a tasty taster, here's a screenie of my first upload, an Openbox theme for use with Espresso GTK theme, by SpecKtacle, over on gnome-look.org.

Enjoy!
From My Little Desktop Photos