Making the Pidgin Tray Icon Show Status in Lubuntu


On these Lubuntu Linux versions (and possibly others), the Pidgin tray icon never changes to show your status or notify you of unread messages.

  • Lubuntu 11.10 (Oneiric Ocelot)
  • Lubuntu 11.04 (Natty Narwhal)
  • Lubuntu 10.10 (Maverick Meerkat)


Pidgin uses its own names for status icons (eg. status/22/pidgin-tray-busy.svg) rather than the standard ones (eg. panel/22/user-busy-panel.svg) and doesn’t fall back to its default ones if they are missing… it just uses the application icon for any ones it can’t find.

The default Lubuntu icon theme (lubuntu) is a very minor tweak on the elementary-mono-dark theme and neither elementary nor elementary-mono-dark provide symlinks to offer the filenames Pidgin expects.


To make the tray icon show status, symlink the standard panel icons to the names Pidgin expects. There seems to be no standard panel status icon for “message waiting”, but since the Pidgin application icon in elementary is a purple speech balloon with an exclamation mark in it, the fallback works perfectly.

I’ve written a little script to automate the process. Run it to fix your lubuntu, elementary and elementary Dark themes. To fix other themes, just edit the two lines near the bottom which tell it where the themes are.

If you want to track the progress of getting this issue fixed upstream, I’ve filed a bug.

UPDATE: The icon theme bug got WONTFIX’d over it being an application-specific thing. Here’s the pidgin bug I filed.

I’ve made sure both bugs reference each other and now I want to try to distance myself from the issue. However, if you happen to read this months later and there doesn’t seem to be any progress made, please give them a polite nudge via the proper channels to let them know people care about it.

CC BY-SA 4.0 Making the Pidgin Tray Icon Show Status in Lubuntu by Stephan Sokolow is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.

This entry was posted in Geek Stuff. Bookmark the permalink.

6 Responses to Making the Pidgin Tray Icon Show Status in Lubuntu

  1. Pingback: Polishing up the Lubuntu Notification Area | Stephan Sokolow's Blog

  2. Shideneyu says:

    Oh man I’m so happy I was just wondering of how I could possibly manage to do that, I googled my problem and 30 minutes ago, I find your freshly new article 😀

    You make my day =]
    (Mmh, in fact it’s 11pm where i’m posting this comment (france), soo, I don’t know if I could say this: you make my night xD Seriously, I can sleep in peace.)

    • Glad I could help. It took me a while to figure it out and nobody else seemed to have done it, so blogging about my solution was the least I could do.

      Greetings from Ontario, Canada. I’m only starting to learn to speak French, but, since I’m a bit of a language geek, let me offer some advice on how to use “you made my day” like a native English speaker.

      First, just use “day” regardless of what time it is. “My day” is a figure of speech that refers to the period of time from when you wake up to when you go back to sleep. (I could go into more detail if you want.)

      Second, you used the wrong form of “make”. (Present tense in this case would be “are making” but we don’t say that.) Here are all of the forms of that phrase that native speakers use:

      “You made my day” or “You’ve made my day” (I’m not an expert on the rest of the world, but in North America, the full-length version, “You have made my day”, is only used emphatically or sarcastically.)

      “This/that made my day”, “This makes my day”, “This will make his/her day”, “That would make his/her day”

      (“This makes my day” is usually only used in reference to something that isn’t complete. For example, if a friend or family member surprises you by taking you to a nice restauraunt, you might say it as you’re entering.)

      “That made their days”, “This will make their days”, “That would make their days”

  3. shideneyu says:

    In fact, I didn’t use the script you’ve made (for I’m on Ubuntu Natty (gnome)), but I have finally understood thanks to you why the pidgin status wasn’t displayed on the tray (I linked the necessary files to get it work =D) , after having searching a long time, you’re the only one who gave a proper solution with a lot of details

    Hey actually, I understand better the expression “You’ve made my day”; I was also hesitating when I’ve written that, I was asking myself “Should I write “you make my day” or “you made my day”; you solved the problem when you answered me even I didn’t asked =]

    I understand the whole process behind that expression; I’m now mastering the art of using this sentence ;D .

    I’m studying english for 9 years now. I’m a 18 student in my first year of computer studies.

    It is a pleasure for me to have been able to get your tip on this question, thanks you my Canadian friend

    Thanks you for everything =)

  4. Iuri says:

    Thanks for the helpful post. I’m not very handy with python and ended up translating it into bash to make sure it wouldn’t do something unexpected, thought others might find this one-liner version handy:

    for f in $(find /usr/share/icons/ -name ‘user-*-panel.*g’); do dir=$(dirname $f); file=$(basename $f); ext=${file##*.}; rad=${file##user-}; rad=${rad%-panel.$ext}; sudo ln -s “$f” “$dir/pidgin-tray-$rad.$ext”;done

    • Thanks. I do have bash experience but I’ve generally found it a lot more difficult to make things work reliably with bash.

      For example, the Python version handles spaces, tabs, and newlines in paths without a problem while yours will break if it ever runs across such odd filenames and looping through ANY filename that a POSIX-compliant filesystem will allow is tricky to get right.

      Even assuming that newlines will never show up in filenames, you still want to play “better safe than sorry” and quote your variable assignment and spaces.

      dir="$(dirname $f)";
      file="$(basename $f)";

      Looking back on that code, I definitely could have made it more concise.

      Here’s a version that’s roughly equivalent (there are a few subtly different behaviours but nothing major) that I’ve boiled down and provided equivalent bash shell code for. If you’re interested, this should really improve your understanding of Python.

      # Unnecessary in bash but sort of like "source"
      import os, glob, re
      # Only call sudo once for the entire script
      #$ if [ "$EUID" != 0 ]; then exec sudo "$0" "$@"; fi
      if os.geteuid() != 0: 
          os.execvp('sudo', ['sudo'] + sys.argv)
      #$ ICON_DIR="/usr/share/icons"
      ICON_DIR = "/usr/share/icons"
      #$ ICON_NAME_SED="s@user-\(.*\)-panel.\(.*\)$@pidgin-tray-\1.\2@"
      ICON_NAME_RE = re.compile('user-(.*?)-panel.(.*?)')
      #$ for theme in elementary{,-mono-dark}; do
      for theme in ['elementary', 'elementary-mono-dark']:
          #$ src_base="${ICON_DIR}/${theme}/panel"
          #$ tgt_base="${ICON_DIR}/${theme}/status"
          # (os.path.join avoids hard-coding / as the path separator)
          src_base = os.path.join(ICON_DIR, theme, "panel")
          tgt_base = os.path.join(ICON_DIR, theme, "status")
          #$ for size_dir in "$src_base"/*; do
          for size_dir in os.listdir(src_base):
              #$ src_size_base="${src_base}/${size_dir}"
              #$ tgt_size_base="${tgt_base}/${size_dir}"
              src_size_base = os.path.join(src_base, size_dir)
              tgt_size_base = os.path.join(tgt_base, size_dir)
              #$ for icon in "$src_size_base"/user-*-panel.*; do
              # Originally I didn't use glob because I wanted to share the same
              # match pattern between this and the name rewriting to ensure that,
              # if it matched, it was guaranteed to be renamed properly for the copy.
              for icon in glob.glob(src_size_base + "/user-*-panel.*"):
                  #$ dest_dir="$(dirname \"$tgt_size_base\")"
                  dest_dir = os.path.dirname(tgt_size_base)
                  #$ tgt_name=$(sed "$ICON_NAME_SED" < << "$(basename \"$icon\")")
                  tgt_name = ICON_NAME_RE.sub(r'pidgin-tray-\1.\2',
                  #$ tgt_path="${tgt_size_base}/${tgt_name}"
                  tgt_path = os.path.join(tgt_size_base, tgt_name)
                  #$ if [ ! -e "$dest_dir" ]; then mkdir -p "$dest_dir"; fi
                  if not os.path.exists(dest_dir):
                  #$ if [ -f "$tgt_path" ] || [ -L "$tgt_path" ]; then 
                  #$     rm -rf "$tgt_path"
                  #$ fi
                  # Safety check to ensure that we don't delete a directory
                  if os.path.isfile(tgt_path) or os.path.islink(tgt_path):
                  #$ ln -s "$icon" "$tgt_path"
                  # Originally I used os.path.relpath to make the symlink relative
                  # so that the icon theme could be moved without breaking it but
                  # I don't know how to make a path relative to another path in the
                  # shell so I left it out here for clarity.
                  # This version is a bit fragile, since it relies on ICON_DIR
                  # always being an absolute path, but I think you get the idea.
                  os.symlink(icon, tgt_path)
              # Python uses indentation to indicate block structure
              #$ done
          #$ done
      #$ done

      Aside from having arrays that are much easier to work with, the main reasons I use Python aren't actually needed for this script.

      Specifically, it's got os.walk (let's you use a simple loop to recursively traverse a directory tree), subprocess (ultra-simple way to call subprocesses without worrying about shell metacharacter exploits), and try/except/finally (when paired with subprocess.check_call, a very clean way to do error handling and ensure cleanup of temporary files).

      ...not to mention having stuff that bash has but some scripting languages miss like the high-level stuff in shutil.

Leave a Reply

Your email address will not be published. Required fields are marked *

By submitting a comment here you grant this site a perpetual license to reproduce your words and name/web site in attribution under the same terms as the associated post.       Also, please be aware that non-constructive comments will have their URL field erased before being approved in order to combat SEO spam.