Shinobu’s Secrets

January 1, 2010

Zsh: univ_open: A Universal Directory/File Opener (no more bashrun)

Filed under: Linux, Productivity/Perspectives — Tags: , , , , , , , , — Shinobu @ 7:45 am

Like my previous post, the goal is to use a single alias to open up any kind of file or directory intelligently. I’ve decided to write a new post because of various improvements over the old code. For one, I’ve implemented everything in Zsh — now everything is much faster, especially for older systems. So now the components are: (1) a custom zsh function called univ_open and (2) some custom options in ~/.zshrc to complement univ_open.

Here is the new univ_open:

 1 # Author: Shinobu (http://zuttobenkyou.wordpress.com)
 2 # Date: December 2009
 3 # License: PUBLIC DOMAIN
 4 # Program Name: univ_open
 5 # Description: open up directories and files intelligently
 6 
 7 univ_open() {
 8     ls="ls -Ahs --color=auto"
 9     if [[ -z $@ ]]; then
10         # if we do not provide any arguments, go to the home directory
11         cd && ${=ls}
12     elif [[ ! -e $@ ]]; then
13         # go to the nearest valid parent directory if file does not exist; we
14         # use a while loop to find the closest valid directory, just in case
15         # the user gave a butchered-up path
16         d=$@:h
17         while [[ ! -d $d ]]
18         do
19             d=$d:h
20         done
21         cd $d && ${=ls}
22     elif [[ -d $@ ]]; then
23         cd $@ && ${=ls}
24     else
25         case $@:e:l in
26             (doc|odf|odt|rtf)
27                 soffice -writer $@ &>/dev/null & disown
28             ;;
29             (htm|html)
30                 firefox $@ &>/dev/null & disown
31             ;;
32             (pdf|ps)
33                 evince $@ &>/dev/null & disown
34             ;;
35             (bmp|gif|jpg|jpeg|png|svg|tiff)
36                 eog $@ &>/dev/null & disown
37             ;;
38             (psd|xcf)
39                 gimp $@ &>/dev/null & disown
40             ;;
41             (aac|flac|mp3|ogg|wav|wma)
42                 smplayer $@ &>/dev/null & disown
43             ;;
44             (mid|midi)
45                 timidity $@
46             ;;
47             (avi|flv|ogv|mkv|mov|mp4|mpg|mpeg|wmv)
48                 smplayer $@ &>/dev/null & disown
49             ;;
50             *)
51             vim $@
52             ;;
53         esac
54     fi
55 }

The basic operation of this function remains the same: if no arguments given, go to the home directory (this is cd’s default behavior); if path is invalid, go to the nearest valid parent directory; if path is a valid directory, cd to it; otherwise, it must be a valid file, so open it up with a program based on the file’s extension, and use vim as the default program for unrecognized extensions (or files with no extensions). Again, filename extensions are lowercased to ensure that we are case-insensitive.

Some improvements over the old code: (1) univ_open now correctly handles messed-up, invalid directories by trying to find the closest valid parent directory — this is achieved with a simple while loop, and zsh’s neat little “:h” method to extract the parent directory (same functionality as the UNIX dirname utility); if there is not a single valid directory in the given path, then it will simply cd into the current directory (i.e., nothing happens); (2) the file extensions are handled much better depending on filetype — for commands that are GUI-based, we redirect its STDOUT and STDERR to /dev/null to silence any error messages, immediately background it with the “&” operator, and finally disown it so that we can continue other work from the same terminal where we used our alias from. Terminal-bound commands, such as timidity and vim, are left as-is.

The neat thing about this new version of univ_open is that this makes bashrun for me obsolete! I can do pretty much everything from the terminal as it is.

And now, the pertinent options in ~/.zshrc to complement our use of univ_open:

fpath=(~/.zsh/func $fpath) # add ~/.zsh/func to $fpath
autoload -U ~/.zsh/func/*(:t) # load all functions in ~/.zsh/func
zmodload zsh/complist
setopt auto_menu
unsetopt listambiguous
zstyle ':completion:*' menu select=1 _complete _ignored _approximate
zstyle ':completion:*' list-colors ${(s.:.)LS_COLORS}
bindkey -M menuselect '^M' .accept-line
LISTMAX=9999
alias d='univ_open' # alias to use univ_open()

auto_menu enables the menu selection system after pressing TAB. unsetopt listambiguous makes zsh automatically complete an ambiguous word to the nearest, partial-word match (combined with auto_menu, this makes it so that you only have to type TAB once, and only once, in all situations). The zstyle lines affect the style of how the menu is displayed. The bindkey portion makes the ENTER key execute the command when using the menu. (Note, ^M is a special character that represents a newline; in vim, you have to type CTRL-V, then CTRL-M to insert it). Finally, setting LISTMAX to a high number prevents zsh from asking “do you wish to see all N possibilities?”, unless N > 9999.

Happy zsh-ing!

UPDATE January 13, 2010: If you’re in a hurry, then you can put bindkey ‘\t’ menu-expand-or-complete to make it so that pressing TAB once brings up the menu and select the first item in that menu. (Or, if there is just 1 possibility, then to expand to that item).

December 5, 2009

Zsh and Ruby: Toward a universal directory/file opener

Filed under: Linux, Productivity/Perspectives, Ruby — Tags: , , , , , , , — Shinobu @ 9:36 pm

This post has been deprecated. Please read this post instead.

I’ve been using Linux for a while now (almost 2 years?), and have learned quite a bit about it. However, ever since I switched to Xmonad as my window manager, I’ve always been tied to the “urxvt + zsh” GUI. Don’t get me wrong — I really enjoy this setup (a plain old terminal has a beauty all of its own in how things get done), but it could be even better.

Lately, I’ve noticed my ~/.zshrc file grow larger and larger, with the addition of new aliases to open up common programs, like “m” for mplayer (audio, movies) and “e” for evince (PDF’s). To get rid of this clutter, and also to automate things, I decided to make a new, simple alias to handle pretty much everything I throw at it. The new functionality lets Zsh, with the help of Ruby, open up just about any file I throw at it, while also integrating the common “cd” command for directories — all from the command line.

The required files/code are as follows: (1) a custom zsh function (autoloaded into your zsh session) and (2) a custom Ruby script. I’ve only tested this on Ruby 1.9.1p243 (2009-07-16 revision 24175) [x86_64-linux].

For the custom zsh function, here is how I autoload it from ~/.zshrc:

fpath=(~/.zsh/func $fpath) # add ~/.zsh/func to $fpath
autoload -U ~/.zsh/func/*(:t) # load all functions in ~/.zsh/func

The function itself is as follows:


 1 # Author: Shinobu (http://zuttobenkyou.wordpress.com)
 2 # Date: December 2009
 3 # License: PUBLIC DOMAIN
 4 # Program Name: univ_open()
 5 # Description: zsh function to open up either directories or files
 6 univ_open() {
 7     ls_pretty="ls -Ahs --color=auto"
 8     if [[ ! -e $@ ]]; then
 9         # go to the parent directory if given path does not exist
10         /home/shinobu/syscfg/shellscripts/sys/univ_handler.rb $@ "parent" | read parent
11         cd $parent && ${=ls_pretty}
12     elif [[ -d $@ ]]; then
13         cd $@ && ${=ls_pretty}
14     else
15         # if it does exist, but is not a directory, open it up with the
16         # universal readerscript, to execute an appropriate program for the
17         # extension
18         /home/shinobu/syscfg/shellscripts/sys/univ_handler.rb $@ "extension" | read outputcmd
19         # since zsh does not split words by default, we need to manually do
20         # this by invoking outputcmd with the ${=VAR} syntax; this is because
21         # univ_handler will sometimes give a multi-word command where we use
22         # one or more commandline options, such as "mplayer -loop 0" or
23         # "soffice -writer" -- to prevent zsh from interpreting the entire
24         # string as the name of a command, we have to split it up into an array
25         ${=outputcmd} $@
26     fi
27 }

The file that contains this function is also called “univ_open”, which resides in ~/.zsh/func/. Anyway, this function is quite simple — it checks to see if the given argument does not exist (line 8), does exist and is a directory (line 12), or does exist and is a file (line 14).

In the “if” statement at line 8, it calls our custom Ruby script, univ_handler.rb, with an argument called “parent”. For lines 12-13, we don’t need to intelligently handle anything since the given argument is a valid directory path, so we just “cd” into it. Lastly, if the argument is a valid file (line 14), we call univ_handler.rb with the “extension” argument to determine which command to use to open up that file.

The univ_handler.rb file looks like this:


 1 #!/usr/bin/ruby
 2 # Author: Shinobu (http://zuttobenkyou.wordpress.com)
 3 # Date: December 2009
 4 # License: PUBLIC DOMAIN
 5 # Program Name: univ_handler.rb
 6 # Description: with the help of smart input from zsh, this script helps zsh
 7 # open up directories and files intelligently
 8 
 9 class Ext
10     @doc = %w{doc odf odt rtf}
11     @web = %w{htm html}
12     @pdf = %w{pdf ps}
13     @img = %w{bmp gif jpg jpeg png svg tiff}
14     @img2 = %w{psd xcf}
15     @audio = %w{flac mp3 wma}
16     @midi = %w{mid midi}
17     @movie = %w{avi flv ogg mkv mov mp4 mpg mpeg wmv}
18 
19     class<<self; attr_reader :doc end
20     class<<self; attr_reader :web end
21     class<<self; attr_reader :pdf end
22     class<<self; attr_reader :img end
23     class<<self; attr_reader :img2 end
24     class<<self; attr_reader :audio end
25     class<<self; attr_reader :midi  end
26     class<<self; attr_reader :movie end
27 end
28 
29 file = ARGV.shift
30 arg = ARGV.shift
31 
32 # zsh will read whatever we ultimately "print" to STDOUT!
33 if file.nil? # if the user does not specify an argument
34     print ""
35 else # figure out file extension, or if directory, the parent directory
36     if arg == "extension"
37         case file.split(".").last.downcase
38         when *Ext.doc
39             print "soffice -writer"
40         when *Ext.web
41             print "firefox"
42         when *Ext.pdf
43             print "evince"
44         # image files -- typical simple files for plain viewing
45         when *Ext.img
46             print "eog"
47         # image files -- ones meant to be edited (strange looking ones and also
48         # gimp's native format)
49         when *Ext.img2
50             print "gimp"
51         # audio files
52         when *Ext.audio
53             print "mplayer -loop 0"
54         # midi files
55         when *Ext.midi
56             print "timidity"
57         # movies
58         when *Ext.movie
59             print "mplayer -loop 0"
60         else
61             # use vim to access files by default, including those without an
62             # extension
63             print "vim"
64         end
65     elsif arg == "parent" # find the closest valid parent directory
66         if file.scan("/").empty? # if there is no "/" in the argument
67             print "." # let's keep the user in the same directory
68         else # if we have a filename (at least the user thinks so), but it is
69              # not a valid file path = file.split("/")
70             path.pop
71             # return 1 directory higher than this one -- we assume that the
72             # reader used tab completions enough to avoid having more than 1
73             # bad directory/file level (that only the text following the last
74             # "/" is invalid)
75             print path.join("/")
76         end
77     end
78 end

You don’t even need to know Ruby to see what’s going on. The important thing is what’s inside the curly braces — we simply group common extensions together based on the file they usually represent. We don’t bother with uppercased combinations, since we use Ruby’s String class’s “downcase” method on the original user-given argument before handling it. Since I love vim, I use it as the “catch-all” to open up any other kind of file (such as files that don’t have extensions).

Now, the most important part — the one alias to rule them all (in your ~/.zshrc):

alias d='univ_open' # alias to use univ_open()

And… that’s it! All you have to do is now do d [file, directory, path, symlink to either a directory or path] to open it up intelligently! I personally use “d” since historically I’ve used it to cd into a directory (and used “k” to go back up); I also find using my middle finger much easier to press keys than my index finger. Probably the best benefit of this setup is that you can do “d TAB TAB …” to go deep into directories, and then just press ENTER when you find the file you want to edit — no more cd-ing deep into a subdirectory first, and then doing “ls” on it to see what’s inside, and deciding which command to use to open up that file. Now it’s just “d” and away you go.

It took me about half a day to get everything working, with help from googling, of course. I hope you can make use of it as it is, or even better, to customize it to your own needs. There’s enough “foundation” code in there with enough complexity to let anyone customize it a great deal and add more extensions to it.

As an added bonus, notice how the code here does not mention symlinks at all — and yet they are handled properly (don’t you love symlinks?)).

UPDATE December 6, 2009: Apparently, there is a similar command line script to open anything called “gnome-open”: http://embraceubuntu.com/2006/12/16/gnome-open-open-anything-from-the-command-line/. You can open up URLs in addition to directories and files. I don’t really see the advantages of opening up a URL from the command line, though — I’m already on Xmonad and going to my supremely powerful Firefox + Vimperator setup is at most 2 or 3 keystrokes away. Still, it looks interesting.

UPDATE December 31, 2009: This post has been deprecated. Please read this post instead.

November 30, 2009

Updated Autolily Script

Filed under: Lilypond, Linux, Ruby — Shinobu @ 8:42 pm

This is an update to my previous post. Now, Autolily’s single argument is no longer required to be the bare *.ly filename itself, but instead may optionally include a path! See the embedded comments in the source code below. Enjoy!


 1 #!/usr/bin/ruby
 2 #===============================================================================================================#
 3 # Program name: Autolily                                                                                        #
 4 # LICENSE: PUBLIC DOMAIN                                                                                        #
 5 # This program takes 1 argument, the name of a lilypond file (*.ly), and watches it for changes every 1 second. #
 6 # If there has been any change, it simply calls lilypond on it to create a new .pdf/.ps/.midi of it.            #
 7 #                                                                                                               #
 8 # Place this script somewhere, like in ~/scripts                                                                #
 9 # Then, open up a terminal and call it like so: ~/scripts/autolily.rb [file]                                    #
10 # [file] must be a LilyPond file (.ly), but it can be located anywhere -- i.e., you may include paths in your   #
11 # file, such as "~/sheet-music/classical/bach2.ly" or "../../bach3.ly".                                         #
12 #                                                                                                               #
13 # You might want to do a "sudo ln -s" of autolily.rb to one of your system's $PATH directories (e.g., /usr/bin) #
14 # to avoid typing out the path to autolily.rb every time you use it. Continuing the example from above,         #
15 # something like "sudo ln -s ~/scripts/autolily.rb /usr/bin/autolily" should do (make sure that                 #
16 # /usr/bin/autolily does not exist already, as the above comman will overwrite that file if it exists).         #
17 #                                                                                                               #
18 # Now you can just do:                                                                                          #
19 #                                                                                                               #
20 #     autolily [file]                                                                                           #
21 #                                                                                                               #
22 # from anywhere in your system!                                                                                 #
23 #                                                                                                               #
24 # To exit, press CTRL-C.                                                                                        #
25 #===============================================================================================================#
26 
27 if ARGV.size > 0
28     file_data_orig = ""
29     file = ARGV.shift
30     pathsize = file.split("/").size
31     ls_call = "ls --full-time"
32 
33     # make sure that the "file" variable is a filename, and not mixed with its path
34     if pathsize > 1
35         path_to_file = file.split("/").first(pathsize - 1).join("/")
36         file = file.split("/").last
37         ls_call << " #{path_to_file}" # modify our `ls` command to reflect relative location of file
38     end
39 
40     `#{ls_call}`.split("\n").each do |line|
41         if line.split(/\s/).last == file
42             file_data_orig = line
43             break
44         end
45     end
46     file_data_new = ""
47 
48     # enter infinite loop -- keep compiling the given lilypond file if it has changed in the past 1 second
49     while true
50         # detect the file size and also timestamp
51         lsarr = `#{ls_call}`.split("\n")
52         lsarr.shift # get rid of the first line, since that is the size of all the files in the directory
53 
54         # find our file from ls's output!
55         lsarr.each do |line|
56             if line.split(/\s/).last == file
57                 file_data_new = line
58                 break
59             end
60         end
61 
62         # if there is any change detected, run lilypond on it
63         if file_data_orig != file_data_new
64             puts "\n\e[1;4;38;5;226mAutolily: Change detected in given file; invoking lilypond...\e[0m\n"
65             if pathsize > 1
66             `lilypond "#{path_to_file}/#{file}"`
67             else
68             `lilypond "#{file}"`
69             end
70             file_data_orig = file_data_new
71         end
72         sleep 1
73     end
74 else
75     puts "No .ly file specified.\n"
76 end

October 26, 2009

Auto-update/make/compile script for Lilypond: Autolily

Filed under: Lilypond, Linux, Ruby — Shinobu @ 1:59 am

I’v so far used Lilypond twice to make nice, clean music of some classical pieces. If you don’t know what Lilypond is already, it is basically LaTeX, but for music. Since the music notation style is almost always the same across many different genres, LaTeX’s “what you see is what you mean” philosophy applies particularly well to your sheetmusic-making needs.

The basic way you work is — create an .ly file pursuant to the lilypond format, then save it, then call “lilypond [filename]” on it from the terminal, which will generate a .pdf, .ps, and .midi output all for you (that is, if you have a “\layout {}” and also a “\midi {}” in you “\score {}”). If you have dual monitors, then you can open up the .pdf file with evince, and then evince will automatically update to the latest .pdf version by itself (no need to close and re-open the same generated .pdf file).

This workflow is nice, but it could be better. For one, it takes time to switch windows and invoke “lilypond [filename]” every time you want to see a small change done. For me, I like to make sure at least every 1/2 measure or so that what I put in is correct. Thus, switching back and forth between all these windows every 30 seconds makes the whole process very time consuming.

So I wrote a small ruby script (I call it “Autolily”) to automatically invoke lilypond for me:


 1 #!/usr/bin/ruby
 2 #===============================================================================================================#
 3 # Program name: Autolily                                                                                        #
 4 # LICENSE: PUBLIC DOMAIN                                                                                        #
 5 # This program takes 1 argument, the name of a lilypond file (*.ly), and watches it for changes every 1 second. #
 6 # If there has been any change, it simply calls lilypond on it to create a new .pdf/.ps/.midi of it.            #
 7 #                                                                                                               #
 8 # Place this script somewhere, like in ~/scripts                                                                #
 9 # Then, open up a terminal and call it like so: ~/scripts/autolily.rb [lilypond file]                           #
10 # Be sure to call it from the directory where the lilypond file is located -- i.e., don't do [path/to/file]     #
11 #                                                                                                               #
12 # To exit, type CTRL-C.                                                                                         #
13 #===============================================================================================================#
14 
15 if ARGV.size > 0
16     file = ARGV.shift
17     file_data_orig = ""
18     `ls --full-time`.split("\n").each do |line|
19         if line.split(/\s/).last == file
20             file_data_orig = line
21             break
22         end
23     end
24     file_data_new = ""
25 
26     # enter infinite loop -- keep compiling the given lilypond file if it has changed in the past 1 second
27     while true
28         # detect the file size and also timestamp
29         lsarr = `ls --full-time`.split("\n")
30         lsarr.shift # get rid of the first line, since that is the size of all the files in the directory
31 
32         # find our file from ls's output!
33         lsarr.each do |line|
34             if line.split(/\s/).last == file
35                 file_data_new = line
36                 break
37             end
38         end
39 
40         # if there is any change detected, run lilypond on it
41         if file_data_orig != file_data_new
42             puts "\n\e[1;4;38;5;226mAutolily: Change detected in given file; invoking lilypond...\e[0m\n"
43             `lilypond "#{file}"`
44             file_data_orig = file_data_new
45         end
46         sleep 1
47     end
48 else
49     puts "No .ly file specified.\n"
50 end

This very simple script is an infinite loop which takes snapshots of the output of the "ls" command every second, and monitors any changes. Only the output line for the given lilypond file is monitored. Whenever this single line changes (any time you save your file, thus changing the modification timestamp of the file), the "lilypond [filename]" command is invoked to generate the .pdf, .ps, .midi outputs.

Now, every single time you save your .ly file, Autolily will run lilypond for you in the background, letting you know of any errors or such (and if you have evince open on the generated .pdf file, evince will update what your sheet music looks like as well).

Memory usage of this script is a bit embarrassing -- I get around 4.5 MB -- but hey, that's Ruby's fault.

Enjoy!

UPDATE November 12, 2009: Added quotes around _file_ so that a filename with spaces works correctly. (Though, if you're a Linux guy like me, you probably don't name your files with spaces in them.)

October 4, 2009

Linux Dual Monitor Setup: Nvidia & Xinerama Guide: Rotating just one monitor

Filed under: FYI, Linux — Shinobu @ 10:55 pm

I have 2 LCD monitors (both are widescreen) hooked up to an Nvidia card in Linux. For a while, I rotated both of them into a “portrait” view, because, aside from the other benefits a portrait view can give (to webpages and documents), putting two widescreens on a landscape configuration takes up too much horizontal space.

But yesterday, I decided to take a hybrid approach and put my left monitor in landscape view, but my right one into portrait view — i.e., I only wanted one monitor rotated 90 degrees. Of course, this is fairly straightforward in Windows with the proprietary Nvidia utility, but it takes a little bit of work with Linux. I googled around a bit, and found this page. I couldn’t really understand what was going on by just looking at the sample xorg.conf file on that page, so I decided to write out my usual in-depth explanation on the matter.

First, to get this hybrid approach, you have to use Xinerama, and NOT Nvidia’s popular TwinView utility/configuration. This is because TwinView (in Linux) only allows you to rotate BOTH monitors together in the same direction.

The only thing you have to do is edit your /etc/X11/xorg.conf file. First, if you already have TwinView set up to work in a dual monitor configuration, you have to run sudo nvidia-settings, and then change from “TwinView” to “Separate X screen” under the “X Server Display Configuration” settings, like so:

2009-10-04-133053_914x657_scrot

The reason we do this (if you already have nvidia-settings installed) is because it auto-generates a working xorg.conf for us. The thing is, under TwinView, you just have 1 option for everything in Xorg — i.e., you just have Device0, Screen0, Monitor0, but now with the “Separate X screen”, you have Device1, Screen1, etc. Not only that, but your old, irrelevant TwinView settings will be automatically deleted or commented out, so it will save you a couple minutes of work (and any typos as well — typos will prevent X from booting!). After that, it’s just a matter of tweaking the xorg.conf file to suit your needs. (BTW, the reason why the right monitor looks like it’s not aligned vertically correctly with the one on the left is because of a manual adjustment — it’s the 333 pixel shift adjustment I made; read on below for more on that).

Here is my current, working xorg.conf with just 1 monitor rotated:

  1 Section "ServerLayout"
  2     Identifier     "Layout0"
  3     #Screen      0  "Screen0" RightOf "Screen1" # put it on the RIGHT (other options are Below, Above, LeftOf, RightOf;
  4                                                 # alternatively, you can put an absolute, pixel X and Y offset (so RightOf
  5                                                 # would be 1680 0
  6     Screen      0  "Screen0" 1680 0 # NOTE: Screen 0 MUST be defined BEFORE Screen 1!!!
  7     Screen      1  "Screen1" 0 333 # put this screen on the top left, but adjust it down a little bit to match the portrait screen on the right
  8     InputDevice    "Keyboard0" "CoreKeyboard"
  9     InputDevice    "Mouse0" "CorePointer"
 10 EndSection
 11 
 12 Section "Files"
 13 EndSection
 14 
 15 Section "Module"
 16     Load           "dbe"
 17     Load           "extmod"
 18     Load           "type1"
 19     Load           "freetype"
 20     Load           "glx"
 21 EndSection
 22 
 23 Section "ServerFlags"
 24     Option         "AutoAddDevices" "False"
 25     Option         "Xinerama" "1"
 26 EndSection
 27 
 28 Section "InputDevice"
 29 
 30     # generated from default
 31     Identifier     "Mouse0"
 32     Driver         "mouse"
 33     Option         "Protocol" "auto"
 34     Option         "Device" "/dev/psaux"
 35     Option         "Emulate3Buttons" "no"
 36     #Option         "ZAxisMapping" "4 5" # for the Logitech MX 400
 37 EndSection
 38 
 39 Section "InputDevice"
 40     Identifier     "Keyboard0"
 41     Driver         "kbd"
 42     Option         "XkbModel" "pc105"
 43     Option         "XkbLayout" "us,fr,de"
 44     Option         "XkbOptions" "grp:shifts_toggle"
 45 EndSection
 46 
 47 Section "Monitor"
 48     Identifier     "Monitor0"
 49     VendorName     "Unknown"
 50     ModelName      "Acer X222W"
 51     HorizSync       31.0 - 81.0
 52     VertRefresh     56.0 - 75.0
 53     Option         "DPMS"
 54     Option         "Rotate" "Right" # for portrait mode
 55 EndSection
 56 
 57 Section "Monitor"
 58     Identifier     "Monitor1"
 59     VendorName     "Unknown"
 60     ModelName      "Acer X222W"
 61     HorizSync       31.0 - 81.0
 62     VertRefresh     56.0 - 75.0
 63     Option         "DPMS"
 64 EndSection
 65 
 66 Section "Device"
 67     Identifier     "Device0"
 68     Driver         "nvidia"
 69     VendorName     "NVIDIA Corporation"
 70     BoardName      "GeForce 8800 GTS"
 71     Option         "RandRRotation" "on"
 72     BusID          "PCI:1:0:0"
 73     Screen          0 # i.e., the monitor on the RIGHT (physically)
 74 EndSection
 75 
 76 Section "Device"
 77     Identifier     "Device1"
 78     Driver         "nvidia"
 79     VendorName     "NVIDIA Corporation"
 80     BoardName      "GeForce 8800 GTS"
 81     BusID          "PCI:1:0:0"
 82     Screen          1 # the monitor on the LEFT (physically)
 83 EndSection
 84 
 85 Section "Screen"
 86 
 87     Identifier     "Screen0"
 88     Device         "Device0"
 89     Monitor        "Monitor0"
 90     DefaultDepth    24
 91     Option         "metamodes" "DFP-0: 1680x1050 +0+0"
 92     SubSection     "Display"
 93         Depth       24
 94     EndSubSection
 95 EndSection
 96 
 97 Section "Screen"
 98     Identifier     "Screen1"
 99     Device         "Device1"
100     Monitor        "Monitor1"
101     DefaultDepth    24
102     Option         "metamodes" "DFP-1: 1680x1050 +0+0"
103     SubSection     "Display"
104         Depth       24
105     EndSubSection
106 EndSection
107

Probably the most important options are the “Screen” options under the “ServerLayout” section — these define which monitor starts where, and the relationship between the two monitors. The “Screen” options are defined by a X-axis (horizontal) and Y-axis (vertical) offset — you can only use positive numbers, I think, and so this means that if a screen is defined as “0 0″, it is on the top left corner of the imaginary monitor “plane,” so to speak. I.e., increasing the X-axis offset moves your screen to the right, whereas increasing the Y-axis offset moves your screen down. For me, my left monitor is slightly adjusted down by 333 pixels, so that it matches up smoothly with my rotated monitor on my right (my setup, physically, looks like a sideways “T”). I’m not sure if the “RandRRotation” option is necessary — it probably is not — I’m too lazy to check after fiddling with my xorg.conf all day yesterday. The other options should be self-explanatory, along with the comments.

Here are some of the not-so-obvious details: for me, my “DFP-1″ is my LEFT monitor and “DFP-0″ is my RIGHT monitor. Apparently, the “primary display” is by default DFP-o (e.g., in Windows, the Nvidia utility detects DFP-o (my RIGHT monitor) as screen “1 of 2″, so I have to manually set DFP-1 (2 of 2) as my primary screen) — the only reason why I have it like this is because for some reason, my BIOS stuff shows up on DFP-1, and not the default “primary” DFP-0, and I’ve always liked my BIOS to show up on my LEFT screen by default — hence the reason why DFP-1 is on my left and DFP-0 is on my right. I hope that made sense. It probably didn’t, so here is a screenshot:

2009-10-04-141105_2730x1680_scrot

Each monitor has a resolution of 1680×1050, but now, my virtual desktop has a 2730×1680 resolution (1680 + 1050 = 2730). DFP-0 is physically rotated so that the bottom side sticks out to the far right — i.e., it’s rotated counter-clockwise 90 degrees — so that the clean, button-less bezel of its top area matches up nicely with the unrotated DFP-1.  And so, we rotate “Right” under the “Monitor” section for Screen 0. This is probably the most sensible way for most people, since almost all monitors that do have buttons at all (to make an uneven, fatter bezel where the buttons are) have them at the bottom of the monitor.

Here are the advantages that you get with Xinerama in the above setup:

  • Moving the mouse from the right to the left is always continuous and seamless. This is even true when moving from the far edges of the portrait monitor into the widescreen one (see notes in screenshot). Finally, the virtual screen behaves EXACTLY like how the monitors look in the real world. (This behavior is available in Windows; however, there are two shortcomings that are not found in Xinerama: (1) when the mouse is on the top or  bottom edge of the portrait monitor, your mouse becomes “stuck” and does not transition smoothly over to the widescreen monitor on the other side (see screenshot above); (2) even though you can adjust the monitors by simply dragging the icons around (which is very user-friendly, I must say), the adjustments are very course and you cannot adjust things down to the last pixel.)
  • Maximizing a window maximizes to the monitor’s area (i.e., the window maximizes up to either the landscape or portrait view), and not the big, virtual landscape of 2730×1680 pixels; even the applications behave intelligently!

A (temporary) disadvantage:

  • Since I’m using Xmonad as my window manager, popup dialog boxes automatically spawn to to the top-left of the virtual screen — i.e., if they’re small enough, they fit entirely into the unviewable area on the top edge. I have to manually flatten the image into the tiled area to see the contents of it. However, this is Xmonad’s fault, and there is probably a hack out there to fix this sort of thing. Even so, since I don’t really use GUI applications that have a lot of popup dialog boxes in the first place, this is a non-issue.

For a long time I thought that Xinerama was an ATI thing, but apparently, it works for Nvidia as well. The xorg.conf layout looks much nicer, and simpler with Xinerama, and is much more flexible with it (e.g., the 333 pixel shift). If you change the few lines in my xorg.conf above that deal with rotations, you could even do without TwinView as well and just use Xinerama for a basic dual-head setup without any rotated screens.

September 14, 2009

Nvidia & Rotated Screen Partial Workaround

Filed under: FYI, Linux — Tags: — Shinobu @ 6:51 am

Currently, there is a bug in the latest Nvidia drivers for Linux. It is the bug described in the following threads:

I suffer from the same “border anomalies” because I too, use Xmonad and Nvidia drivers, with two rotated screens. I lived with the annoyance for a few months (I even emailed Nvidia a bug report), until, by accident, I discovered a partial workaround — for all urxvt terminal windows. Since I usually do all my important work in urxvt terminal windows anyway (only exceptions being firefox and maybe OOo Writer), it really is a lifesaver. The fix for urxvt windows is as follows: in your ~/.Xdefaults file, put in the following property for urxvt’s resources, like so:

urxvt*depth: 32

For some reason, this fixes the strange border behavior completely for all urxvt windows in Xmonad. I stumbled on this workaround when trying to make my urxvt windows transparent (which don’t work for me — probably because I use xwinwrap to play a screensaver permanently in the background).

BTW, I also use the option “urxvt*fading: 33″ to make inactive windows fade out a bit, even though this setting is a bit buggy at the moment (probably as a result of the xwinwrap thing and also how Nvidia’s drivers are still messing things up in the first place). Still, the fading option is worth a try if you haven’t done so yet — it’s much faster to recognize active urxvt windows than from just using xmonad’s border’s alone (I use a 1-pixel wide white/black border in xmonad).

UPDATE November 11, 2009: Nvidia’s latest driver, 190.42, seems to have fixed this issue. Rotated screen + border issue has been resolved according to their changelog, and I have noticed the change myself in my desktop’s rotated monitor.

August 24, 2009

Xwinwrap + Xmonad = Less Deadness

Filed under: Linux — Shinobu @ 8:36 pm

If you use Xmonad, you’ll notice that there is just a dark, black screen for the background on any unused workspace. I must admit, it didn’t bother me much at first, but after a couple of months it got really boring. My computer felt very quiet, and very… dead. I then considered setting up a wallpaper or something to make my desktop look more engaging. Though it is certainly possible to spice it up with a simple background image/wallpaper, it is also possible to put up a movie or screensaver (or any other program). How, you say? With Xwinwrap.

I actually use shantz-xwinwrap-bzr from the AUR (Arch Linux User Repository) to set up a screensaver in the background. Specifically, I use the following call:

xwinwrap -ov -fs -ni -- /usr/lib/xscreensaver/cubicgrid -root -window-id WID -delay 10000 -speed 0.5 -ticks 35 &

This displays the “cubicgrid” screensaver, which is part of the xscreensaver package. The beauty of xwinwrap is that you can use not just a screensaver, but any other program with it. For example, you could, if you wanted, play a movie (or a playlist of movies) in the background, constantly. Though your monitor would then resemble a PC from BestBuy or Costco, playing movies in the background is certainly possible. The only cons are:

  • Uses 5-10% of your CPU, depending on what program you are running.
  • If you are using a standard Desktop Environment like KDE, Gnome, or XFCE, all of your desktop icons will not be displayed, as they will be underneath the xwinwrap window (although you could still see them via transparency — though I have not done this myself).
  • “Cool” effects become a bit boring after a while (the xmatrix screensaver, for example, looks cool for about 5 minutes, but then gets annoying — maybe this is just me though).

I guess a more traditional approach to this technique would be to set up a slideshow of your family’s digital photo album, if you have one. The possibilities are endless.

July 23, 2009

Enable HQ Quality on any Youtube video

Filed under: FYI — Shinobu @ 1:39 am

Just add “&fmt=18″ to the video’s URL.

This is especially useful for screencasts done by programmers with small text.

June 26, 2009

On Sleep

Filed under: Productivity/Perspectives, Rant — Shinobu @ 12:36 am

The wave of interest in recent times of so-called polyphasic sleep has become very pervasive. I’ll have to admit that even I took keen interest in it around the time I started this blog. I’ve read countless articles on sleep, and now, I’ve come to the following conclusion: the problem is not figuring out the bare minimum of hours of sleep you need each day; rather, the real problem is figuring out how you can be more active/productive while awake. If you cannot confidently say “I spend all of my awake-time doing productive things”, then there is no point of “hacking” your day so that you sleep less hours; what’s the point of buying more books if you cannot finish reading the ones you have already?

I think most people initially accept the proposition that if you sleep less, you’ll get more done. The common one-liner you’ll read in most articles goes something along the lines of “even if you shave off just 1 hour off of your usual sleeping cycle, this meager saving will net you X extra years of life!

This kind of thinking is plain wrong. Unless you are narcoleptic, sleeping too much is NOT the problem. The real problem is figuring out what you are going to do while you are awake. You can sleep 6 hours, 4, hours, 2 hours even, in a single day. Nobody cares. The only thing you should care about is how you spend your time.

Now, I do understand that for some people, spending more hours out of bed will guarantee more productivity. But this is only true if the pending task is very simple and does not require much decision-making. Unfortunately (or fortunately, rather), very few people in the modern world today share the same working career as child laborers did at the dawn of the Industrial Age. Unless a supervisor directs all of your attention to predefined goals from the minute you wake up to the minute you go to bed, so that you are reduced to a drone working for the Hive, sleeping less does NOT mean increased productivity.

Besides, there are far more important problems to tackle than “hacking” your brain to get less sleep:

  • How can I spend more quality time with my family?
  • How can I stay healthy?
  • How can I improve my relationship with my partner?
  • How can I improve my mind?
  • How can I conquer my fears?
  • How can I stop procrastinating?
  • …etc.

None of these important questions involve sleep as a material part of the solution. Sleep, my friend, is irrelevant. All of the questions above instead have the goal of increasing the quality of life. So don’t fool yourself into thinking that sleeping less is an integral part of self-improvement. Sleep, like everything else in life that can be objectively quantified, must be taken in moderation.

June 21, 2009

Arch Linux: Clean up those .pacnew and .pacsave files

Filed under: Linux — Shinobu @ 12:55 am

Once in a while, pacman gives messages about some system config file, and the creation of either a .pacnew or .pacsave file (or sometimes a .pacorig file). The reason why this happens is because your system upgrade results in conflicting configuration files — pacman is smart enough to realize that it would be very dangerous to simply overwrite your configuration files automatically with the new ones from the newer package(s). A good example is GRUB’s menu.lst file — you certainly would NOT want to delete the old (unupgraded) one, since it holds all your valuable data about which partition to boot from, and as well as any other operating systems you use under GRUB. So, how should you take care of them — after all, the newer config files DO often contain newer settings and options.

The answer: install the yaourt package from AUR if you haven’t already. Then, issue the command yaourt -C. This will take care of all those pesky config files via an interactive shell session. Yaourt will let you view the original config file, and the .pacnew or .pacsave variant of it, using a variety of programs — including gvim and vim. I use gvim because my default colorscheme in vim is too dark for displaying the diffs properly. Simply do CTRL + W, W in normal mode to switch between the two windows (copy and paste to quickly merge long sections).

You should get in the habit of doing yaourt -C every time you encounter a message about a .pacnew or .pacsave.

Older Posts »

Blog at WordPress.com.