Category Archives: Computers

Multiple X (Desktop) Sessions in Ubuntu

This post has a lot to do with graphics but there are no graphics. It’s a walk-through explanation and and proof of concept of some very interesting features of Linux as a desktop operating system.

If you aren’t familiar with X, than this webpage might confuse you, the X Window System is what draws the GUI (graphical user interface) for Ubuntu. On top of this, you may have a Window Manager or Desktop Environment, such as Gnome (Ubuntu default) or KDE (Kubuntu).

When you boot up Ubuntu, it creates a set of “virtual terminals”. These VTs are accessible via a key combination of clt+alt+f1-12. VT7 (ctrl+alt+f7) is the default and it handles X’s “screen 0″. If you play around, with the key combination, you’ll notice you drop into consoles with a login prompt (f1-6) or a blank screen (f8-f12, don’t worry if you see USB errors).

These virtual terminals used to be handled by X which was slower and more prone to crash (citation needed) but since Ubuntu 8.04, this has been handled by “Kernel Mode”, where this management is handled by the kernel. You can switch to another virtual terminal and create another X session.

Typically in Linux, you could switch to another VT, login [as another user] and type $ startx — :1 (special argument ‘--‘ marks the end of client arguments and the beginning of server options, :1 defines screen 1). This will work in Ubuntu but the part where I found it failing was switching between this newly created X session and back to my original :0 on VT7.

The way I found to do this in Ubuntu seems a bit counter-intuitive. Before I explain, you should create a new user, if you don’t have another already. You can do this by going to System > Administration > Users and Groups.

To create a second X session in Ubuntu, go to your logout menu (default top right) and select “switch user”, and login as another user (you don’t want to create an error in the user environment). When you login as another user, Ubuntu creates a screen :1 on VT8. This means, you can change back to VT7 with ctrl+alt+f7, then back to VT8 with ctrl+alt+f8. I suspect this is the reason VT8-12 show up as blank screens instead of login terminals. Ubuntu seems to be leveraging the power of virtual terminals for “user switches”.

I haven’t noticed much in performance loss doing this and the other big question is practicality. Why would you ever do this? Perhaps you are testing software and want isolated test cases or you want a dedicated user for games with a more streamlined window manager and want to be able to flip back and forth.

Similar areas I came across in my research were Nested X sessions and Multiseat X.

Random gnome-terminal profiles (themes) in Ubuntu

Introduction

Does it ever confuse you if you have too many terminals open at once that look alike? Perhaps you’re just looking to express your personality or tickle your brain. In any case, if you’re using the terminal in ubuntu a lot, you may be interested in having random profiles (colors / settings).

The concept of the method is pretty simple, define a hotkey that launches a script that picks a random profile you’ve created and then open the terminal with that profile as a parameter.

Prerequisites

- Compiz or other hotkey script that will allow you to link to a .sh file
- gnome-terminal
- bash

Getting Started

You can figure out what Profiles you have by going to Edit > Profiles in gnome-terminal. You likely only have one, “Default”, unless you’re already actively using terminal profiles. If you only have one, you should create a few, maybe 3 or 4 right now and play with the colors a bit. Important, don’t include spaces in the names of the profiles

The Script

Create a file in your scripts folder (or create a directory if you don’t have one):

mkdir ~/scripts
touch ~/scripts/gnome-terminal.sh && chmod +x ~/scripts/gnome-terminal.sh
gedit ~/scripts/gnome-terminal.sh

Paste the following replacing the Profile names with those of your own (delimited by spaces) and change the number 4 to that of the :

#!/bin/bash
p=( Default Delta Psi Sigma )
gnome-terminal --window-with-profile ${p[$((RANDOM%${#p[@]}))]}

That ugly looking bit right here is a calculation between a random number (echo RANDOM) and the size of the array (${#p[@]}), “random” % “length of array”. Where % means mod, or remainder of the division. (examples: 7%4 = 3; 6%4 = 2; 5%4 = 1; 4 % 4 = 0; 4 % 3 = 1; 321%321= 0).

To illustrate more, play with this code:

r=$RANDOM; echo $r; echo $((r % 4))

This is how we get a random index value for the array. This value is nested inside the array ${p[r]}, where r is the random, within bounds, array index. That array then corresponds with a name of our profile and we pass it as a paramater to gnome-terminal with “–window-with-profile”. So using my define array above, if the random index were “1″, “Delta” would be echoed. If the index were “0″, Default would be.

The Setup

Now, I use compiz with the commands plugin, setting my “command line 0″ to ~/scripts/./gnome-terminal.sh and my “run command 0″ under my key bindings tab to ctrl+alt+t, but you can associate this script with anything you’d like to kick it off. A shortcut icon for example.

May this inspire you to understand, extend and share.

Restricting a user’s shell permissions on Ubuntu Server 10.04 with lshell

As described by apt-cache, the method which I usually begin a package search for in a Ubuntu Server 10.04 environment:

z@zentury ~$ apt-cache search lshell
lshell - restricts a user's shell environment to limited sets of commands

This is an extremely useful way to restrict a Linux users capabilities. Alternative shells, such as rssh, limit you to toggle a specific set of applications, (scp, sftp, cvs, svn, rsync or rdist). A limited shell is helpful for reasons such as backups or game/application servers where you know/want the user to be able to execute only a specific set of actions. You can however, consider other reasons for restricting users on a Linux based machine.

A typical use case is provided in the lshell wiki.

Ubuntu also provides a default in etc/lshell.conf, which serves as a good example:

# lshell.py configuration file
#
# $Id: lshell.conf,v 1.20 2009/06/09 19:53:46 ghantoos Exp $

[global]
##  log directory (default /var/log/lshell/ )
logpath         : /var/log/lshell/
##  set log level to 0, 1, 2 or 3  (0: no logs, 1: least verbose)
loglevel        : 2
##  configure log file name (default is %u i.e. username.log)
#logfilename     : %y%m%d-%u


[default]
##  a list of the allowed commands or 'all' to allow all commands in user's PATH
allowed         : ['ls','echo','cd','ll']

##  a list of forbidden character or commands
forbidden       : [';', '&', '|','`','>','<', '$(', '${']

##  number of warnings when user enters a forbidden value before getting 
##  exited from lshell
warning_counter : 2

##  command aliases list (similar to bash’s alias directive)
aliases         : {'ll':'ls -l', 'vi':'vim'}

##  a value in seconds for the session timer
#timer           : 5

##  list of path to restrict the user "geographicaly"
#path            : ['/home/bla/','/etc']

##  set the home folder of your user. If not specified the home_path is set to 
##  the $HOME environment variable
#home_path       : '/home/bla/'

##  update the environment variable $PATH of the user
#env_path        : ':/usr/local/bin:/usr/sbin'

##  allow or forbid the use of scp (set to 1 or 0)
#scp             : 1

##  allow of forbid the use of sftp (set to 1 or 0)
#sftp            : 1

##  list of command allowed to execute over ssh (e.g. rsync, rdiff-backup, etc.)
#overssh         : ['ls', 'rsync']

##  logging strictness. If set to 1, any unknown command is considered as 
##  forbidden, and user's warning counter is decreased. If set to 0, command is
##  considered as unknown, and user is only warned (i.e. *** unknown synthax)
#strict          : 1

##  force files sent through scp to a specific directory
#scpforce        : '/home/bla/uploads/'

If this looks like something you would like to be able to do, you can install it with apt-get:

z@zentury ~$ apt-get install lshell

You can change a current user to have the limited shell with the following command:

sudo chsh -s /usr/bin/lshell backupbot

You can add a new user with a limited shell with the following command (-m creates the home directory):

sudo useradd -m -s /usr/bin/lshell backupbot

A more detailed configuration guide can be found here

The Best Way to Tweet to Twitter, Post on Facebook from WordPress

I’ve been focusing some time recently to the foundation levels of Internet marketing. I’m aiming to increase visibility as strongly as possible at the core of a website giving it the power to leverage evolving trends as simply as possible. This of course means utilizing APIs from other web applications, such as social networks. The title of this post is true but deceptive. I consider the following method the best way to tweet from WordPress but it’s actually a whole lot more than that. It’s a gateway to a large number of social media applications; one account to rule them all. ping.fm is a service that allows you to link multiple social network websites, such as facebook, twitter, linkedin and more.


+ twitter

So the idea then, is to leverage then is to utilize the ping.fm application from your website. If you’re using WordPress then you’re set, the simple no frills publish 2 ping.fm plugin will allow you to interact with ping.fm from your blog/website.

I’ve tested this out with the free open-source GPL First Person Shooter, Xonotic and a new site I just started dumbtubes.com. Both have twitter accounts that you can see publishing twitter.com/dumbtubes, twitter.com/xonotic. Xonotic also publishes to many other social accounts, see the Xonotic homepage to find other accounts.

Stay tuned for more wordpress tips.

WARNING, this plugin may cause other plugins options panels not to work. I’m not sure the cause yet but be aware that it can cause the sub settings of dedicated plugin setting groups to throw access errors.

Python Multi-head X (Nvidia TwinView / Dual Monitor) Development Notes

Preface

The following development notes were written after researching the underlying handling of dual monitors in the X window system on Linux. I’ve included a code snippet that I built to help demonstrate behavior and create a proof of concept to show I can determine which monitor a window is on using only python and no statically set coordinates.

Introduction

I mentioned in my previous post that I’m using an nVidia video card with “TwinView” software that outputs my video as if it were one screen, which it technically is, one X screen. This means that the distinction between monitors is not mapped in the X tree, it’s handled by the window manager. Unlike Xinerama, which has an x session per monitor and stitches them together. Xinerama, however, has is being deprecated in favor of RandR but regardless, TwinView is my choice and is not an option for me to change to.

With all of that said, the decision to bridge python to c that interfaces with compiz is a deadend and would be better implemented based on the new 0.9.0 C++ api. It would be nice to be able to return a list of windows from a “monitor” object. However, that’s beyond my current scope. I was able to whip up some python that to show that implementing the monitor management in python using the gtk module isn’t /that/ hacky. I emphasize because I read some posts that claimed window decorations could be an issue in accurate calculations.

Some Code

Read the comment on line 2. Learn more about pygtk here

#!/usr/bin/python
# Print some information about the X environment, the monitor setup, currently active window and cursor position
import gtk.gdk

screen = gtk.gdk.screen_get_default()
print "X default screen size: %d x %d" % (screen.get_width(), screen.get_height())
print "xid of root window: %d" % screen.get_root_window().xid

monitors = int(screen.get_n_monitors())
print "== %d monitors ==" % monitors
for m in range(0, monitors):
    print " - geometry of monitor %d: %s" % (m, screen.get_monitor_geometry(m))

window = screen.get_active_window()
win_x, win_y, win_w, win_h, win_bit_depth = window.get_geometry()
print "active window on monitor: %d" % screen.get_monitor_at_point((win_x+(win_w/2)),(win_y+(win_h/2)))
print "window geometry (x,y,w,h): %d, %d, %d, %d" % (win_x,win_y,win_w,win_h)

display = gtk.gdk.display_get_default()
pointer = display.get_pointer()
print "cursor position (x, y): %d, %d" % (pointer[1], pointer[2])
print "cursor on monitor: %d" % screen.get_monitor_at_point(pointer[1],pointer[2])

thanks to those in #compiz-dev and #python on freenode who helped me come around to create this snippet. I hope it will help others looking to develop for multi-head setups in Linux. Please let me know if I missed anything or did something incorrectly, this is new territory for me.

Compiz 0.9.0 Released – Completely Rewritten in C++

I was doing some in depth research / code hacking regarding the support of multi-headed output (dual monitors) on Linux. I won’t get into details but my video is being output to my monitors as “one screen” with a virtual distinctions handled by the window manager. Because of this, figuring out which of the monitors you are on isn’t as straight forward as you might think. Originally I was looking for a way to access the c functions in compiz through python but that point is now moot (likely for the better).

The first unstable release of the Compiz 0.9 series, completely rewritten in C++. As said, this “brings a whole new developer API, splits rendering into plugins, switches the buildsystem from automake to cmake and brings minor functionality improvements. This release represents the first developer and tester preview of what will eventually make the 0.10.x stable series. Please note that as such, it is not yet ready for general use as there are a number of known ssues, regressions and incomplete functionality.”

Here is a SLIGHTLY DATED graph I got from Santiance.com.

This is a really interesting turning point for the project and I’m glad I came across this while doing my research for multi-head handling in compiz. Knowing where the future lies could drastically change where I put my efforts in developing to support them.

New Python eBook, Much Better, Down and Dirty

Some friends recommended a book that’s a quicker pace with some better programming practices. Learn Python The Hard way (or quick way :-P). It reads more like a walk-through tutorial / quick reference and gives you easily repeatable programming practices that will get you a stronger feel for the language. It’s probably best used in combination with the Python Documentation. Also, a fair warning, Dive Into Python has war declared against it.

scp-notifications for GNOME and Ubuntu – Expanding on My Original Python Script

I’ve only been coding Python for ~12 hours total, so don’t expect this to be perfect. Knowing what I know about creating/testing other software and doing my best to scour through very light pynotify documentation, I’ve begun to build out this script to be more useful / portable / configurable. As the Version 0.6 indicates, I’m not quite at my goal yet and there is still more to learn to bring it up to that point.

I’m releasing this early on my blog just in case I caught any people yesterday who’ve been experimenting with my research / code so far. I’ll share it on github when I evolve it just a bit more.

Video of it in Action

#!/usr/bin/env python
#
# Title: scp-notifications
# Author: Tyler Mulligan (tyler@detrition.net)
# Date: 06/26/2010
# Version: 0.6
# Description:
# Used in combination with an event, such as an action or cronjob, this script
# will scp the latest file from a folder to your server.
#
# Optionally, it can copy the url to your clipboard and/or show a popup with a
# link to the file after succesfully uploading
#
# Orginally developed to be piped to from compiz screenshot tool
# http://interwebninja.com/videos/compiz-screenshot-piped-to-notification-daemon-for-upload.ogv
#
# The MIT License
#
# Copyright (c) 2010 Tyler Mulligan
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE
#

import pygtk
pygtk.require('2.0')
import pynotify
import gtk
import sys
import os
import subprocess

# Set Variables
#####################################
user = "user"
host = "server.com"
# All should have trailing slashes
lfolder = "/home/user/screenshots/"
hfolder = "/home/remote_user/screenshots/"
httplink = "http://"+host+"/screenshots/"


# Display
#####################################
t1 = 5000 # timeout for screenshot upload dialog
t2 = 3000 # timeout for screenshot preview
t3 = 7000 # timeout for link dialog

screenshot_preview = 1 # If using with the compiz screenshot plugin, you may want this
popup_link = 1 # another popup
copy_to_clipboard = 0 # automatically copy text to keyboard

# Position
#####################################

# Get screensize < < used for relative positioning
display = gtk.gdk.display_get_default()
screen = display.get_default_screen()
x = screen.get_width() - 1
y = screen.get_height() - 1

# 0 for Automatic Placement
"""
x1 = 0
y1 = 0
x2 = 0
y2 = 0
x3 = 0
y3 = 0
"""
# Define Relative Position (assuming top-right)
x1 = x-1
y1 = 12
x2 = x1
y2 = y1 + 100
x3 = x-1
y3 = 12
# Define Static (1920 puts it on my second monitor)
"""
x1 = 1919
y1 = 12
x2 = x1
y2 = y1 + 100
x3 = 1920
y3 = 12
"""
#####################################

def upload_cb(n, action):
    assert action == "upload"

    subprocess.call(["scp", os.path.join(lfolder, f), '%s@%s:%s' % (user, host, hfolder)])

    # setup URL in
    if copy_to_clipboard:
        clipboard = gtk.clipboard_get()
        clipboard.set_text(httplink + f)
        # make our data available to other applications
        clipboard.store()

    # Notification: Link for the clicking
    if popup_link:
        n3 = pynotify.Notification("Here is your link","<a href='" + httplink + f + "'>" + httplink + f + "")

        helper = gtk.Button()
        icon = helper.render_icon(gtk.STOCK_DIALOG_INFO, gtk.ICON_SIZE_DIALOG)
        n3.set_icon_from_pixbuf(icon)

        n3.set_urgency(pynotify.URGENCY_NORMAL)
        if x3:
            n3.set_hint("x", x3)
        if y3:
            n3.set_hint("y", y3)
        n3.set_timeout(t3)
        n3.connect("closed",closen3_cb)

        if not n3.show():
            print "Failed to send notification"
            sys.exit(1)

        closen1_cb(n1)
        closen2_cb(n2)

    gtk.main_quit()
    sys.exit(1)

# Notification 1 was closed
def closen1_cb(n):
    n1.close()
    if screenshot_preview:
        n2.close()
    gtk.main_quit()

# Notification 2 was closed
def closen2_cb(n):
    n2.close()
    gtk.main_quit()

# Notification 2 was closed
def closen3_cb(n):
    n3.close()
    gtk.main_quit()

# The Ignore button was clicked
def ignore_cb(n, action):
    assert action == "ignore"

    closen1_cb(n1)
    closen2_cb(n2)
    gtk.main_quit()

# Main
def main():
    gtk.main()

# Init
if __name__ == '__main__':
    if not pynotify.init("Notifier 'scp' Option"):
        sys.exit(1)

    # Get latest file and build uri
    start = os.path.abspath(lfolder)
    f = max([(os.path.getmtime(os.path.join(start,p)),p)
         for p in os.listdir(start)])[1]
    uri = lfolder + f

    # Notification: Upload to Server
    n1 = pynotify.Notification("Upload to Server?","Copy the file '" + f + "' to the server?")

    helper = gtk.Button()
    icon = helper.render_icon(gtk.STOCK_DIALOG_QUESTION, gtk.ICON_SIZE_DIALOG)
    n1.set_icon_from_pixbuf(icon)

    n1.set_urgency(pynotify.URGENCY_NORMAL)
    if x1:
        n1.set_hint("x", x1)
    if y1:
        n1.set_hint("y", y1)
    n1.set_timeout(t1)
    n1.add_action("upload", "Yes, Upload", upload_cb)
    n1.add_action("ignore", "Ignore", ignore_cb)
    n1.connect("closed",closen1_cb)

    if not n1.show():
        print "Failed to send notification"
        sys.exit(1)

    # Notification: Screenshot Preview
    if screenshot_preview:
        n2 = pynotify.Notification("Screenshot Preview", "", uri)
        n2.set_urgency(pynotify.URGENCY_LOW)
        if x2:
            n2.set_hint("x", x2)
        if y2:
            n2.set_hint("y", y2)
        n2.set_timeout(t2)
        n2.connect("closed",closen2_cb)

        if not n2.show():
            print "Failed to send notification"
            sys.exit(1)

    main()

.

Ubuntu Notifications (osd-notify) Sucks, notifications-daemon Rocks – Exploiting the Goodness with Compiz

Introduction

The long name for this blog used to be “Tyler Mulligan’s Tips and Tricks for Increasing your Efficiency“. I love finding ways to increase my efficiency and let computers do the work while I focus on more interests aspects of what the computer is providing me with. When I recognize an issue, I find a way to cut out time by streamlining the process for the most accurate repetition, like any programmer would/should/could.

I noticed myself taking a lot of screenshots with compiz’ built in screenshot tool (I can hold a hotkey and drag a box to take newspaper style clippings). This is very fast and simple, I highly recommend enabling this option and getting used to it. However, I don’t care much for clicking around on clunky websites to upload images.

This is where my adventure starts… when I find out a very useful feature was deprecated and not replaced in Ubuntu. I don’t use the new notification area, it has too much I don’t need, I never liked the behavior of these new osd-notify notifications which I found out now are even more worthless (sorry team).

Using Sane Notifications in Ubuntu

After reinstalling the GNOME default notifications system in Ubuntu I was able to use SANE notifications that actually… KICK ASS! I don’t understand how osd-notify is better than these which even comes with it’s own notification properties panel. Maybe it’s an under the hood thing…

Regardless, there is no doubt in my mind that notifications that you hover, can still slightly see but click through but cannot perform any actions, even a close, are just plan stupid and annoying..


Screenshot of the script I ended up writing using the “better” notification system to ask me if I want to upload the screenshot I just took to the server.

Linking the notifications

I linked the notifications the following way:

Python Script for Notification that Prompts for File Upload to Server

Knowing diddly squat about Python, I chugged forward with my classic notification popups that allow for interaction as it had the most activity around it and some examples available in /usr/share/doc/python-notify/examples/

I ended coming up with the following script thanks to some help from a few people in #python on irc.freenode.org

This is outside of the scope of this blogpost but this script assumes you have setup passwordless ssh to your server.

#!/usr/bin/env python
#
# Title: Notification 'scp' Option
# Author: Tyler Mulligan (tyler@detrition.net)
# Date: 06/25/2010
# Description:
# Used in combination with an event, such as an action or cron
# the latest file from a folder will be scped to your server and will copy
# the http location of the that file to your clipboard
#
# Orginally developed to be piped to from compiz screenshot tool
#
#
# The MIT License
#
# Copyright (c) 2010 Tyler Mulligan
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE
#

import pygtk
pygtk.require('2.0')
import gtk
import pynotify
import sys
import os
import subprocess

user = "user"
host = "server.com"
lfolder = "/home/user/screenshots/"
hfolder = "/home/remote_user/screenshots/"
httplink = "http://"+host+"/screenshots/"
timeout = 5000

# Set position
display = gtk.gdk.display_get_default()
screen = display.get_default_screen()
x = screen.get_width() - 1
y = screen.get_height() - 1
#x = 1919
#y = 12

def upload_cb(n, action):
    assert action == "upload"

    start = os.path.abspath(lfolder)
    f = max([(os.path.getmtime(os.path.join(start,x)),x)
          for x in os.listdir(start)])[1]

	# setup URL in clipboard
    clipboard = gtk.clipboard_get()
    clipboard.set_text(httplink + f)
    # make our data available to other applications
    clipboard.store()

    os.system('scp "%s" "%s@%s:%s"' % (lfolder + f, user, host, hfolder) ).wait()

    n.close()
    gtk.main_quit()

def ignore_cb(n, action):
    assert action == "ignore"
    n.close()
    gtk.main_quit()

if __name__ == '__main__':
    if not pynotify.init("Notifier 'scp' Option"):
        sys.exit(1)

	# Setup Popup
    n = pynotify.Notification("Upload to Server?")
    n.set_urgency(pynotify.URGENCY_NORMAL)
    n.set_timeout(timeout)
    n.set_category("device")
    n.add_action("upload", "Yes, Upload", upload_cb)
    n.add_action("ignore", "Ignore", ignore_cb)

    # Set position
    n.set_hint("x", x)
    n.set_hint("y", y)

    if not n.show():
        print "Failed to send notification"
        sys.exit(1)

    gtk.main()

edit: I updated the script with some position information — I love that I can put the notifications ANYWHERE on my screen. I also variablized the timeout.

edit 2: Here is a video of my improved script in action — I’ll post the source later

http://interwebninja.com/videos/compiz-screenshot-piped-to-notification-daemon-for-upload.ogv

Going Beyond

The Compiz example is just something that server my immediate needs. The possibilities are however endless. You can for example, link this script to a cron job asking you if you want to sync some other sort of file. Or perhaps you’d like to add multiple buttons to give yourself a folder / server choice.

Happy hacking

Patching NextGEN Voting Plugin to Allow Showing of the Vote Form on Single Images

Intro

NextGEN Voting is a plugin for the wordpress plugin NextGEN Gallery plugin. Keeping this in mind made the task of extending easier. NextGEN Gallery hooks into wordpress functions, NextGEN Voting hooks into NextGEN Gallery.

By default, NextGEN Voting hooks into the gallery view, giving access to a function that uses the image id for lookup. The only reason we see nothing if we try to paste the same template code into a page other than the recommended “nextgen-gallery/view/gallery.php” is because that function is not given access in any other view.

How-to Add Access to Use the Function in the Image Browser Template

Open “wp-content/plugins/nextgen-gallery-voting/ngg-voting.php”,

Look for:

add_filter("ngg_show_gallery_content", "nggv_show_gallery", 10, 2);

Add After:

add_filter("ngg_show_imagebrowser_content", "nggv_show_imagebrowser", 10, 2);

Look for:

function nggv_show_gallery($out, $gid) {
	return $out.nggc_voteForm($gid, $buffer);
}

Add After:

function nggv_show_imagebrowser($out, $gid) {
	return $out.nggc_voteForm($gid, $buffer);
}

Now we have given access to the function and can paste the following code into “wp-content/plugins/nextgen-gallery/imagebrowser.php”:

<?php echo nggv_imageVoteForm($image->pid); ?>

Conclusion

I’ve tried to explain this in method in a way you can repeat an extend to suit your needs. By following the same logic and tracing the hooks, you can apply this however you might need.

You’ll want to keep “wp-content/plugins/nextgen-gallery/nggfunctions.php” open as a reference for what hooks are available. You can find hooks by searching for “apply_filters(‘”, it will be the first parameter.