Make compiz-fusion work with xscreensaver (the quick & dirty way)

Posted in GNU | Linux, HowTo, Open Source on November 23rd, 2008 by Jorge – 6 Comments

The beautiful desktop experience provided by compiz-fusion represents a significant aesthetic contribution to the pleasure of using Linux. Besides, it makes it really easy to impress even the most committed Apple disciple. The same is true for the cool gl screensavers written for xscreensavers. Unfortunately, these two don’t really work together (my computer freezes everytime xscreensaver comes up while running compiz-fusion) and although the screensaver plugin for compiz-fusion shows great potential, the gl collection for xscreensaver is still a bit ahead and has a lot more variety, so I really wanted to make them work together.

Here is what I did:

  1. You can use xscreensaver-command -watch to monitor xscreensaver events, so you can actually run a program when xscreensaver is activated (for example, to disable compiz-fusion), and another one when it is deactivated (to bring compiz-fusion back). I modified the following script available from the xscreensaver man pages and saved it as ~/bin/fixscreensaver:
    #!/usr/bin/perl
    
    # Fixes xscreensaver when compiz is running
    
    my $blanked = 0;
    open (IN, "xscreensaver-command -watch |");
    while () {
      if (m/^(BLANK|LOCK)/) {
        if (!$blanked) {
          system "usemetacity";
          $blanked = 1;
        }
      } elsif (m/^UNBLANK/) {
        system "usecompiz";
        $blanked = 0;
      }
    }
  2. As you can see, the script above calls usemetacity when xscreensaver is activated and usecompiz when it is deactivated. Save the following script as ~/bin/usemetacity:
    #!/bin/bash
    
    #killall gkrellm
    metacity --replace &
    #sleep 1
    #gkrellm &
  3. Now save this one as ~/bin/usecompiz:
    #!/bin/bash
    
    #killall gkrellm
    compiz --replace &
    #sleep 2
    #gkrellm &
    #windowranger
  4. Add ~/bin/fixscreensaver to the list of startup applications (System > Preferences > Sessions > Startup programs) and also make sure that ~/bin/ is in your $PATH environment variable.
  5. Optional: If you use gkrellm, you should uncomment the corresponding lines in the scripts above. Those lines will prevent metacity (the default gnome window manager) and compiz-fusion from changing the position of the gkrellm window, which happens everytime you switch between the two because these window managers use different ways to describe desktop geometry.
  6. Optional: You can also use the usecompiz and usemetacity scripts to manage any other application that misbehaves when metacity or compiz-fusion take over your desktop. In fact, I use the windowranger script below to automatically put windows back into their corresponding viewports since everything gets shoved into the first viewport once you go back into compiz from metacity (thanks for pointing it out darken). You will need wmctrl for this to work properly:
    #!/usr/bin/python
    
    import os, time, wnck, sys
    
    def dec2hex(n):
      #"""return the hexadecimal string representation of integer n"""#
      return "%X" % n
    
    def hex2dec(s):
      #"""return the integer value of a hexadecimal string s"""#
      return int(s, 16)
    
    def MoveWindow(wID, wtitle, xpos, ypos):
    
        time.sleep(0.2)
        os.system('wmctrl -i -r ' + wID + ' -e 0,'+str(xpos)+','+str(ypos)+',-1,-1')
        #time.sleep(0.4)
        #os.system('wmctrl -i -a ' + wID)
        if DEBUG: print "Moved to", xpos, ypos, 'n'
    
    def Place(x, y, wID, wclass, wtitle):
    
      fin,dout = os.popen4('wmctrl -d')   # output desktop geometry
      for line in dout:
        line = line[line.find('VP: ') + 4:len(line)]  # get current viewport offset
        line = line[0:line.find(' ')]
        offset = line.split(',')      # split in x,y viewport offset coordinates
        vpxpos = int(offset[0])       # convert into integer
        vpypos = int(offset[1])       # convert into integer
        absxpos = vpxpos+x            # absolute window position (x)
        absypos = vpypos+y            # absolute window position (y)
        wxpos = absxpos
        wypos = absypos
        while wxpos >= width:
          wxpos = wxpos - width       # relative window position (x)
        while wypos >= height:
          wypos = wypos - height      # relative window position (y)
        if (wxpos >= 0)&(wxpos <= 2): wxpos = 0
        if (wypos >= 0)&(wypos <= 2): wypos = 0
    
      dout.close()                    # close command output
      if DEBUG: print 'Position:', absxpos, 'x', absypos
    
      #Send Firefox to viewport 1
      if wclass.find('Firefox') != -1:
        # Flash fullscreen windows are titled 'Firefox' so we need to ignore them...
        if wtitle != 'Firefox':
          MoveWindow(wID, wtitle, wxpos - vpxpos + vpx1, wypos - vpypos + vpy1)
    
      #Send GYachI to viewport 2
      elif wclass.find('GYachI') != -1:
        MoveWindow(wID, wtitle, wxpos - vpxpos + vpx2, wypos - vpypos + vpy2)
    
      #Send VirtualBox to viewport 5
      elif wclass.find('VirtualBox') != -1:
        MoveWindow(wID, wtitle, wxpos - vpxpos + vpx5, wypos - vpypos + vpy5)
    
      #Send Amarok to viewport 6
      elif wclass.find('Amarokapp') != -1:
        MoveWindow(wID, wtitle, wxpos - vpxpos + vpx6, wypos - vpypos + vpy6)
    
      #Send Azureus to viewport 6
      elif wclass.find('SWT') != -1:
        MoveWindow(wID, wtitle, wxpos - vpxpos + vpx6, wypos - vpypos + vpy6)
    
      #Send Qbittorrent to viewport 6
      elif wclass.find('Qbittorrent') != -1:
        MoveWindow(wID, wtitle, wxpos - vpxpos + vpx6, wypos - vpypos + vpy6)
    
      #Send Pidgin to viewport 7
      elif wclass.find('Pidgin') != -1:
        MoveWindow(wID, wtitle, wxpos - vpxpos + vpx7, wypos - vpypos + vpy7)
    
      #Send Skype to viewport 7
      elif wclass.find('Skype') != -1:
        MoveWindow(wID, wtitle, wxpos - vpxpos + vpx7, wypos - vpypos + vpy7)
    
      #Send Thunderbird to viewport 8
      elif wclass.find('Thunderbird-bin') != -1:
        MoveWindow(wID, wtitle, wxpos - vpxpos + vpx8, wypos - vpypos + vpy8)
    
      #Send all other windows in viewport 1 to viewport 2
      elif (wclass.find('Gnome-panel')==-1)&(wtitle != 'Desktop')&(wclass.find('Gkrellm')==-1)&(wclass.find('Launcher')==-1)&(absxpos < width)&(absypos <= height):
        MoveWindow(wID, wtitle, wxpos - vpxpos + vpx2, wypos - vpypos + vpy2)
    
      else:
        if DEBUG: print 'Ignoredn'
    
    #---------------------------- MAIN -------------------------------------
    s = wnck.screen_get_default()
    width = s.get_width()
    height = s.get_height()
    vpx1 = (width * 0);vpy1 = (height * 0)
    vpx2 = (width * 1);vpy2 = (height * 0)
    vpx3 = (width * 2);vpy3 = (height * 0)
    vpx4 = (width * 3);vpy4 = (height * 0)
    vpx5 = (width * 0);vpy5 = (height * 1)
    vpx6 = (width * 1);vpy6 = (height * 1)
    vpx7 = (width * 2);vpy7 = (height * 1)
    vpx8 = (width * 3);vpy8 = (height * 1)
    DEBUG = False;
    
    for arg in sys.argv:
      if arg=='--debug':
        DEBUG=True;
    
    if DEBUG: print 'Viewport geometry:', width, 'x', height, 'n'
    
    fin,wout = os.popen4('wmctrl -lGx')
    for line in wout:
      wID = line[0:line.find(' ')]                      # get the window ID
      line = line[line.find(' '):len(line)]
      line = line.lstrip()
      wdesk = line[0:line.find(' ')]                    # get the window desktop
      line = line[line.find(' '):len(line)]
      line = line.lstrip()
      wxoffset = line[0:line.find(' ')]                 # get the window x offset
      wxoffset = (int(wxoffset) / 2)
      line = line[line.find(' '):len(line)]
      line = line.lstrip()
      wyoffset = line[0:line.find(' ')]                 # get the window y offset
      wyoffset = (int(wyoffset) / 2) - 24
      line = line[line.find(' '):len(line)]
      line = line.lstrip()
      wwidth = line[0:line.find(' ')]                   # get the window width
      line = line[line.find(' '):len(line)]
      line = line.lstrip()
      wheight = line[0:line.find(' ')]                  # get the window height
      line = line[line.find(' '):len(line)]
      line = line.lstrip()
      wclass = line[0:line.find(' jsilva')]             # get the window class
      line = line[line.find(' jsilva'):len(line)]
      line = line.lstrip()
      whost = line[0:line.find(' ')]                    # get the window host
      line = line[line.find(' '):len(line)]
      line = line.lstrip()
      wtitle = line[0:len(line) - 1]                    # get the window title
      if DEBUG:
        print 'Class:', wclass
        print 'Host:', whost
        print 'Title:', wtitle
      Place(wxoffset,wyoffset,wID,wclass,wtitle)  # place window
    wout.close()
  7. Enjoy!

Activate spelling check in OpenOffice 2.4

Posted in GNU | Linux, HowTo, Open Source on November 7th, 2008 by Jorge – 3 Comments

For some weird reason, activating the spellcheck on OpenOffice 2.4 seems to be more challenging than it should, and since I just got it working in Ubuntu Hardy Heron, I thougth I should post the solution here:

  1. Go to Tools > Options…

    Openoffice tools menu with options entry highlighted

    OpenOffice tools menu with options entry highlighted

  2. Select Language Settings > Writing Aids and click on the Edit… button

    Writing aids dialogue with edit button highlighted

    Writing aids dialogue with edit button highlighted

  3. Check the boxes for the Spelling and Thresaurus modules. This will enable the spellcheck for the language in the Language field, so you should repeat this process with each of the languages you want to use.

    Language module editing dialogue with spelling and thesaurus entries highlighted

    Language module editing dialogue with spelling and thesaurus entries highlighted

  4. You should now see the spellcheck symbol beside your chosen language in the language settings dialogue at Tools > Options… > Language Settings > Language. Enjoy!

    Language settings dialogue with spellcheck symbol highlighted

    Language settings dialogue with spellcheck symbol highlighted

Encode a windows-compatible video

Posted in GNU | Linux, HowTo, Open Source on November 7th, 2008 by Jorge – Be the first to comment

There are a lot of constantly updated video and audio codecs available in Linux. Unfortunately, the choice in Windows is way more limited. Because of this, it is common that videos compressed with the best and latests codecs in Linux cannot be read by common Windows applications. Luckily, You can encode windows-compatible videos in Linux with mencoder by typing the following command:

$ mencoder -oac mp3lame -ovc lavc -lavcopts \
vcodec=msmpeg4v2:vhq:vbitrate=1600 -o videoout.avi videoin.xxx

The Dell D610 lid switch on Ubuntu 8.04

Posted in GNU | Linux, HowTo, Open Source on October 7th, 2008 by Jorge – Be the first to comment

The lid switch makes the laptop’s screen turn off when the lid is closed and turns it back on when the lid opens. This already worked well in Ubuntu but I needed to tweak the behavior a bit. Sometimes I use a projector as the main display and turn off the laptop’s screen to save some battery, however, Ubuntu turns off ALL displays (including the analog output) when the panel lid is closed, which then leaves me with no screen at all!

How it Works

You can determine the state of the lid switch by doing:

$ cat /proc/acpi/button/lid/LID/state

In order to turn on/off the backlight of the LCD panel, you can use radeontool. This tool is part of the Ubuntu distribution so you can install it with Synaptic (if it is not already installed). After installing both, the laptop-mode-tools (also part of Ubuntu) and radeontool packages, I created the following script:

#!/bin/bash

LIGHT=$(radeontool light | grep "looks on")

if [ "$LIGHT" = "" ]; then
        radeontool light on
else
        radeontool light off
fi

This script toggles on/off the backlight of the LCD panel. You can then use xbindkeys to assign a keyboard shortcut and control the LCD backlight at will.

Tweaking the Lid Switch Behavior

In order to set and maintain the state of the backlight when the lid is closed, you can create a daemon and call it with laptop-mode-tools. This is specially handy if some of your applications (usually games) like to turn the panel backlight back on when resetting the video resolution or when going into full screen.

Step 1

Comment everything on /etc/acpi/lid.sh and add the following at the end of the script:

LID_CLOSED=$(cat /proc/acpi/button/lid/LID/state | grep open)
if [ "$LID_CLOSED" = "" ]; then
  /usr/sbin/blightoffd &
else
  /usr/sbin/radeontool light on
fi

Step 2

Save the following script as /usr/sbin/blightoffd

#!/bin/bash

#
# Keeps panel backlight off when computer lid is closed.
#

LID_CLOSED=$(cat /proc/acpi/button/lid/LID/state | grep open)

while [ "$LID_CLOSED" = "" ]; do

  LIGHT_ON=$(/usr/sbin/radeontool light | grep "looks off")
  if [ "$LIGHT_ON" = "" ]; then
    /usr/sbin/radeontool light off
  fi
  sleep 1
  LID_CLOSED=$(cat /proc/acpi/button/lid/LID/state | grep open)

done

Step 3

Disable or uninstall both kpowersave and klaptop.

Making it all work with powersave

I installed powersaved which is great tool for enabling dynamic control of the CPU speed and save additional power. However, that bugger messed up the scripts controlling the lid switch events. Here is how to fix the problem:

Find the following line in /etc/powersave/events:

EVENT_BUTTON_LID_CLOSED="xxxxxxx"

and make sure it says:

EVENT_BUTTON_LID_CLOSED="ignore"

This will make powersave ignore lid switch events

Ukelele tuner for the Gameboy Advance

Posted in Open Source on August 5th, 2008 by Jorge – 1 Comment
GameBoy ukelele tuner screenshot

GameBoy ukelele tuner screenshot

This weekend I went for a relaxing vacation in a cottage somewhere around Haliburton, Ontario. This is usually also a good opportunity for me to try and remember some chords on the Ukelele that my girlfriend bought for my birthday a couple of years ago. The only problem I have is that I don’t know how to tune the thing. Normally, I would go to a site like the online Ukelele tuner before I get started. But without a computer and internet access, I would be stuck with no way to tune the Ukelele in the cottage.

Luckily, after a bit of thinking and half an hour of coding, I came up with a tuner that I flashed into one of the Gameboy Advance units I have for the OpenEADL project (check it out). The tuner worked great, and because the Gameboy is so power efficient, I didn’t have to charge it even once in the whole weekend!

You can download the code for the tuner from here (I included the compiled ukelele-advance.gba ROM). If you want to know how to modify, compile and flash the ROM into a Gameboy cartridge, read this tutorial. You can also run the ROM in an emulator like VisualBoy Advance