Wednesday, October 6, 2010

Gnome Decent Dual Monitor Wallpaper Span

Tired of trying to use compiz to have wallpaper span both screens, only to find your desktop icons disappear?

A few months ago I embarked on a relentless search through mountains of RGBA patches, custom versions of nautilus, and failed attempts at allowing desktop icons to pierce through compiz's iron curtain.

Finally created a decent method of having wallpaper span dual monitors in Gnome by overriding Gnome's "Spanned" desktop setting (I don't think it works right anyway) with a "Zoomed" dual monitor setting.  I first tried this by scaling the image directly, but it looked like crap so I figure Zoom would be better to use.  The result is not perfect, but definitely better than waiting 15 years for the Gnome team to come up with a plausible solution.

The steps I took were for Arch Linux, but you can apply them equally well to any distribution, as long as you know how to make packages from source.

After reading through this bug, I realized I should be modifying the desktop settings directly.

I checked my Gnome version through pacman, and proceeded to download the PKGBUILD straight from the Arch SVN.  After receiving the source code, I ran "makepkg" once to ensure the source would compile properly, then proceeded to comment out the following lines in the PKGBUILD file:

#source=(http://ftp.gnome.org/pub/gnome/sources/${pkgname}/2.32/${pkgname}-${pkgver}.tar.bz2)
#sha256sums=('blahblah')

To ensure that the source code would not be downloaded again & overwrite my modifications.

Next, I proceeded to open the "src/gnome-desktop-2.32.0/libgnome-desktop/gnome-bg.c" file, and commented out the following line, simply copying the Gnome "Zoom" option's code to the "Span" section of the case statement:

#if 0
    g_print ("original_width: %d %d\n",
         gdk_pixbuf_get_width (pixbuf),
         gdk_pixbuf_get_height (pixbuf));
#endif
   
    switch (placement) {
    case GNOME_BG_PLACEMENT_SPANNED:
                // new = pixbuf_scale_to_fit (pixbuf, width, height);
        new = pixbuf_scale_to_min (pixbuf, width, height);
        break;
    case GNOME_BG_PLACEMENT_ZOOMED:
        new = pixbuf_scale_to_min (pixbuf, width, height);
        break;
       
    case GNOME_BG_PLACEMENT_FILL_SCREEN:
        new = gdk_pixbuf_scale_simple (pixbuf, width, height,
                           GDK_INTERP_BILINEAR);
        break;
       
    case GNOME_BG_PLACEMENT_SCALED:
        new = pixbuf_scale_to_fit (pixbuf, width, height);
        break;
       
    case GNOME_BG_PLACEMENT_CENTERED:
    case GNOME_BG_PLACEMENT_TILED:
    default:
        new = pixbuf_clip_to_fit (pixbuf, width, height);
        break;
    } 
Finally, in the next section continaing the "GNOME_BG_PLACEMENT_SPANNED" (around 20 lines down from the previous section), I made the following modification to the code--commenting out what is commented in blue, and replaced with the code in red:

    scaled = get_scaled_pixbuf (placement, pixbuf, dest_width, dest_height, &x, &y, &w, &h);

    switch (placement) {
    case GNOME_BG_PLACEMENT_TILED:
        pixbuf_tile (scaled, dest);
        break;
    case GNOME_BG_PLACEMENT_ZOOMED:
    case GNOME_BG_PLACEMENT_CENTERED:
    case GNOME_BG_PLACEMENT_FILL_SCREEN:
    case GNOME_BG_PLACEMENT_SCALED:
        pixbuf_blend (scaled, dest, 0, 0, w, h, x + area->x, y + area->y, 1.0);
        break;
    case GNOME_BG_PLACEMENT_SPANNED:
        // pixbuf_blend (scaled, dest, 0, 0, w, h, x, y, 1.0);
        pixbuf_blend (scaled, dest, 0, 0, w, h, x + area->x, y + area->y, 1.0);
        break;
    default:
        g_assert_not_reached ();
        break;
    }
   
    g_object_unref (scaled);

From here, I saved the source,  ran "makepkg -f" again, installed the package, and restarted Gnome.  Not perfect, but they are nice ;)

Monday, October 4, 2010

C++ -- Why do we not dereference when passing by reference?

I recently got back into trying to teach myself C++, mostly through YouTube tutorials (this guy's are pretty good).  I only went to IRC for an answer at one point, but would like to share something I found & wasn't able to Google on.

Everyone should know how to use pointers when working with C++.. say we had:

#include
using namespace std;

int main()
{
    int num = 5;
    int *pnum = #
    cout<<"integer num (@"<<<") = "<<*pnum;
    return 0;
}

Then we can see that integer num is set equal to five, and integer pointer pnum is set to the address of num.  Normally, in C++, the "&" operator refers to the address of the object the operator is being applied to.

In the case of passing values to function by reference, I was quite confused when I found that we do not in fact need to dereference the reference passed as an argument.  For example:

#include
using namespace std;

void increment_variable(int & x)
{
        x++;
        return;
}

int main()
{
        int num = 5;

        increment_variable(num);

        cout<<"integer num (@"<<&num<<") = "<<
        return 0;
}

In the increment_variable(int & x) function, we would think that to increment the value of the x variable, we would need to dereference the address of the x variable, which has been passed as a parameter.  As shown by the code, this is not in fact the case! 

 In reality, the "&" operator when used with pointers is a completely different operator than the "&" used when passing values to functions by reference.

Do not get the two confused!