Another wallpaper changer for Gnome and Unity

The previous wallpaper changer that I wrote in Python served me well for the last 2 years, but sometimes it would get stuck with some wallpapers: of the 200 pictures I have in my wallpapers folder (mostly taken from the paper wall), some were definitely being shown more often than others. Has the script developed a taste? Probably! ๐Ÿ™‚

So this time I decided to put together something very quick, but that does a better job at never showing the same picture twice before all pictures in the folder have been set as desktop background.

It comes as a single bash script, there’s no configuration file to set, it picks pictures from a single folder (whereas the Python version could use several), and it moves files to a folder called shown when setting them as desktop background. Not very elegant, but it gets the job done!

Here it is; you can set your wallpapers folder and the refresh interval at the highlighted lines.

#!/bin/bash
#
# WallpaperChanger.sh
# Copyright 2014 Michele Bonazza michele@michelebonazza.com
#
# A simple script to automatically change your wallpaper in Gnome.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

WALLPAPERS_FOLDER=/home/path/to/your/wallpapers
REFRESH_INTERVAL=$((5 * 60)) # change every 5 minutes
MODE="zoom" # one between none, centered, wallpaper, scaled, stretched, zoom, spanned

# Changes the desktop background, and moves it to the "shown" folder so that it's
# not shown again before all wallpapers in the folder have been used.
# arg1 the file name of the file to be set as new background; must be in the
#      current folder
function change_wallpaper() {
  mv $1 shown
  gsettings set org.gnome.desktop.background picture-uri file://$WALLPAPERS_FOLDER/shown/$1
  gsettings set org.gnome.desktop.background picture-options $MODE
}

# Echoes the next wallpaper to be set, picked at random among images in the
# configured folder
function get_next_wallpaper() {
  find . -maxdepth 1 -type f -name "*.png" -o -name "*.jpg" -o -name "*.gif" -o -name "*.jpeg"| shuf -n 1
}

mkdir -p $WALLPAPERS_FOLDER/shown
cd $WALLPAPERS_FOLDER

while true; do
  NEXT_WP=$(get_next_wallpaper)
  
  # have we used all wallpapers?
  if [[ "$NEXT_WP" == "" ]]; then
    # yes, chdir to shown, and move them all back to the parent folder
    cd shown
    # move them to parent folder
    find . -maxdepth 1 -type f -name "*.png" -o -name "*.jpg" -o -name "*.gif" -o -name "*.jpeg" | xargs mv -t ..
    cd ..

    # check again
    NEXT_WP=$(get_next_wallpaper)

    if [[ "$NEXT_WP" == "" ]]; then
      echo "no wallpapers found in $WALLPAPERS_FOLDER, will check again in $REFRESH_INTERVAL seconds..."
      sleep $REFRESH_INTERVAL
      continue
    fi
  fi
  
  echo "changing background to $NEXT_WP"
  change_wallpaper $NEXT_WP
  sleep $REFRESH_INTERVAL
done

As always, I’ve also added this to my pastebin.

Save it as wallpaper_changer.sh, make it executable

chmod +x wallpaper_changer.sh

and add it to your “Startup applications” list, which can be found in Ubuntu’s main menu (the one you use to log out/shut down the computer), or can be brought up from a terminal using

gnome-session-properties

Click “Add”, use whatever name you want and browse to the wallpaper_changer.sh script (wherever you’ve saved it).

Sometimes I found that “Startup applications” doesn’t work: make sure that after having added your script and closed the window you can see an entry called wallpaper_changer.sh.desktop in the output of

ls -l ~/.config/autostart

If it’s not there, remove the entry and try again (I know, I know. The alternative is to fiddle with Upstart or init.d so if you want a GUI, that’s better than nothing!)

You can also change the effect to apply to your wallpapers at line 23 in the script.

Enjoy your new desktops! ๐Ÿ™‚

Advertisements

Disable touch input for a Wacom Bamboo tablet using a Unity launcher (or a Gnome launcher)

I love my Wacom Bamboo graphics tablet, and I really appreciate the fact that it just works in Ubuntu. Palm rejection sort of works, but that “sort of” drives me crazy when I’m using the pen and trigger scrolling by resting my hand on the tablet. I couldn’t find a quick way to disable touch input, something that I can do from a nice GUI window in Mac OS.

After searching some tool to do that, I found the very powerful xsetwacom command, and wrote a very simple script that enables/disables touch.

It goes like this:

#!/bin/bash

DEVICE_ID=$(xsetwacom --list devices | grep TOUCH | egrep -o "id\: [0-9]+" | cut -d" " -f2)

if [[ "off" == $(xsetwacom get $DEVICE_ID touch) ]]; then
    xsetwacom set $DEVICE_ID touch on
else
    xsetwacom set $DEVICE_ID touch off
fi

(should have used awk @line 3, but sometimes I get lazy when writing silly scripts)

Save this file on your user’s home calling it wacom_toggle_touch and make it executable (chmod +x wacom_toggle_touch).

Everytime you run the script, it toggles touch on the tablet. Very neat. But I wanted to just have a graphical button to click, so I created a gnome launcher that just does that; here it is:

[Desktop Entry]
Encoding=UTF-8
Name=Wacom Bamboo Touch
Comment=Toggles touch on a Wacom Bamboo Tablet
Exec=/bin/bash "/home/myuser/wacom_toggle_touch"
Icon=/usr/share/icons/Faenza/devices/scalable/input-tablet.svg
Categories=Application;
Version=1.0
Type=Application
Terminal=0

Name this file wacom-toggle-touch.desktop (the .desktop part is important) and save it to either /usr/share/applications/ or ~/.local/share/applications/, depending on whether you want all users to access the script or only your current user.

I use the cool Faenza theme for my icons, so that explains the icon path @line 6. Here’s the icon if you don’t want to use the theme but you’re looking for an icon that just gets the job done. Download it to some folder and update the path accordingly in the launcher. Also, be sure to update the path to the script @line 5 (for some reason using ~ for your user’s home doesn’t work, you have to type the extended /home/your_username path).

When you’re done, drag the wacom-toggle-touch.desktop file to your Unity bar (I actually use Docky instead, it makes switching between Mac OS and Ubuntu a lot easier on my poor brain) and just click it everytime you want to toggle touch mode!

The same process should work for Gnome as well, just drag the .desktop file to wherever launcher bar you want (assuming Gnome still has launcher bars, they kind of lost me after Gnome 3 so I don’t know).

Remove the “file edit view go bookmarks help” entries from the Gnome 3 top panel

After running the usual apt upgrade the nautilus menu items suddenly appeared below gnome-shell’s top panel. By below I mean that I have a transparent top bar under which the menu items are showing, but can’t be clicked at all.

Following this post (scroll down to the “Fix Nautilus menu being displayed under the GNOME Shell top bar when using transparent GNOME Shell themes” paragraph) I managed to remove them by simply going to the gnome tweak tool and disabling the Have file manager handle the desktop option under Desktop.

I don’t even know why that option has been set on in the first place…

[Edit]: when disabling the Nautilus desktop management option not only icons will disappear from the desktop, but you you won’t be able to right-click and execute scripts either (and with gnome-shell being very unstable with the latest ATI drivers I very often rely on my gnome-shell restart script, so this is a show stopper).

The only solution I found (and I actually had to struggle a bit, since it doesn’t seem to be a very common issue yet) is to set the top panel background to some opaque image or gradient. Since I installed a gnome-shell theme (you can find the option in the gnome tweak tool under Theme/Shell theme) called Nord, the CSS files to be edited can be found inside ~/.themes/Nord/gnome-shell/, and all styles for the top panel are defined in ~/.themes/Nord/gnome-shell/panel.css.

If you don’t have a custom theme you’ll find the top panel background definition in a file with a path like /usr/share/themes/Ambiance/gtk-3.0/apps/gnome-panel.css (change Ambiance with the name of the GTK+ theme you use).

You must find the #panel definition, and change the background- tags to set an alpha (the fourth in rgba values) of 1.0 like I did:

#panel {
    border: 1px solid rgba(0,0,0,0.2);
    background-gradient-direction: vertical;
    background-gradient-start: rgba(84,84,84,1.0); /* note the 1.0 value */
    background-gradient-end: rgba(168,168,168,1.0);
    /* and so on... */
}

Set fullscreen windows to go over gnome-shell’s (and Unity’s) top panel (top bar) with python/C++ and Glade

I know that there’s a function called fullscreen() that you can call on a window to set it fullscreen. I also know that my screen resolution is 1920×1080, so I supposed that explicitly setting the window’s height and width to the exact screen size would have forced mutter to put my window above everything else.

But…

No, it doesn’t. There’s a sneaky little option called Window Type that has to be set to Popup to make gnome’s top bar surrender and let your window dominate the screen. You can find it in the General tab in Glade (it’s the third field in Glade 3.10.0, I don’t know about the other versions).

Is this some kind of common knowledge that doesn’t have to be put on tutorials? I find the lack of documentation on GTK+3 disturbing.. ๐Ÿ™‚ (I know that the API is quite well documented, but we’re still missing the plethora of examples you can find for GTK+2 on the web)

Add a simple restart Gnome Shell script to your right-click menu

After using the behated Unity for too much time I decided to give Gnome3.2 another chance; last time I tried I couldn’t get my cheap integrated Radeon 3000 graphic card to work with all the rendering gnome-shell requires, so I had to pick one of Gnome “classic” or Unity2D. The latter is a little less ugly, albeit suffering from too much rigidity in what you can customize and what you cannot. I tried to like it, I really did, but working with the left dash bar is painful to me.

So, after installing the latest catalyst drivers (12.1) from ATI I’ve been able to use Gnome3, and after tweaking it hard with several extensions (nice system, by the way, but maybe support for browsers other than firefox would help) I now have a desktop that I kinda like. It’s sad that I used to like Gnome2 better, though.

Not speaking of its slow responsiveness (I admit my GPU is no monster, but my PC is 10 months old, so I’d expect it to run whatever window manager… heck, it runs KDE 4 just fine!), what I find astonishing is its instability. Every now and again, gnome-shell screws up for whatever reason, and all window controls are gone, top bar and the gnome-shell itself as well. Switching to another tty with Ctrl+Alt+F1 and logging in with my user to killall gnome-shell is not helping since the gnome-shell process lies in the other session that I’m therefore forced to kill, restarting the gdm process.

At first I used this little hack from phreaknerd’s blog: you schedule a script for automatic execution that checks whether a “delete me if you want to restart gnome-shell” file exists every 15 seconds (so the routine was like: gnome-shell dies, switch to tty1, login, rm polled file, logout, Ctrl+Alt+F7 back to graphic session, wait for the script to find out).

But then I grew tired of waiting the 7.5 seconds (on average :P) for the script to detect that the control file is missing, and of the whole tty switching in general; since I’m always able to right-click on the desktop (if anything on the empty space left by the gone window decorations) I think a better solution is to add a simple script to ~/.gnome2/nautilus-scripts/ (why is it still called gnome2 anyway) like this:

cd ~/.gnome2/nautilus-scripts/; echo -e '#!/bin/bash'"\n"'gnome-shell --replace' > Restart\ gnome-shell; chmod a+x Restart\ gnome-shell

So now all I have to do is right click somewhere on the desktop, choose Scripts/Restart gnome-shell and I can get back to work! ๐Ÿ˜€

I really, really, really hope that 3.4 will be a lot more stable though…

Retrieve the window object from widgets with pygobject / GTK+3

I’m trying to develop a simple app using PyGObject, pyGTK as we used to call it last time I used it.

I must say that I mildly hate Gnome 3 (and Unity, for that matters) and even though there’s certainly been an improvement in the overall quality of the API for GTK+3 the lack of documentation and good tutorials is very depressing. One must always fall back to C documentation and hope that a python function exists with a similar name, or struggle through the source code to look for it.

Rant aside, one thing I wanted to do is to draw on a DrawingArea using Cairo whenever the mouse cursor enters some region. Once I got Glade to signal the motion-notify-event correctly (you have to both set the signal on the ‘signals’ tab and check the option for ‘Pointer Motion’ in the ‘Common’ tab under ‘Events’) I realized that you must create a Cairo context every time the signal handler is called, so that you can draw on it.

Googling and googling (and after stumbling upon the best source for what I wanted to do… even though it’s in Japanese! :D) I found that the easiest solution is to call something like

def onMouseMove(self, widget, event):
  cr = widget.window.cairo_create()
  cr.arc(whatever...)

Unfortunately, an AttributeError: 'DrawingArea' object has no attribute 'window' came up, so after more googling I found out that the new fashion is to call get_property("propertyName") to retrieve its fields… which is not bad in and on itself (if not a little too weakly-typed for my tastes), but it’s not that immediate if you were used to code for GTK+2.

This is what I finally came up with:

def onMouseMove(self, widget, event):
  cr = widget.get_property('window').cairo_create()
  cr.arc(whatever...)

Now I just have to do the rest… ๐Ÿ™‚