Recent posts (max 10) - Browse or Archive for more

LeoCAD 21.06 - Packaged for Linux

LeoCAD is a CAD application for building digital models with Lego-compatible parts drawn from the LDraw parts library.

I packaged (as an rpm) the 21.06 release of LeoCAD for Fedora 34. This package requires the LDraw parts library package.

Install the binary rpm. The source rpm contains the files to allow you to rebuild the packge for another distribution.

leocad-21.06-1ec1.fc34.x86_64.rpm

leocad-21.06-1ec1.fc34.src.rpm

LDraw Parts Library 2020-03 - Packaged for Linux

LDraw.org maintains a library of Lego part models upon which a number of related tools such as LeoCAD, LDView and LPub rely.

I packaged the 2020-03 parts library for Fedora 34 to install to /usr/share/ldraw; it should be straight-forward to adapt to other distributions.

The *.noarch.rpm files are the ones to install, and the .src.rpm contains everything so it can be rebuilt for another rpm-based distribution.

ldraw_parts-202003-ec1.fc34.src.rpm

ldraw_parts-202003-ec1.fc34.noarch.rpm
ldraw_parts-creativecommons-202003-ec1.fc34.noarch.rpm
ldraw_parts-models-202003-ec1.fc34.noarch.rpm

Blinds Tilt Mechanism Repair

We have a large faux-wood blind on our dining room window. The window pane itself is 70"x70"; which makes for a great view. However, the tilt mechanism stopped working in fairly short order. The tilt mechanism uses a pull-cord based mechanism which is no longer offered in blinds. I replaced the mechanism the first time it failed, but when it failed the second time in much the same way, I could no longer find a replacement for the parts. The original mechanism failed because the interface between the cord spool and the shaft driving the worm gear which drove the tilting of the blinds had worn, become loose, and allowed the cord spool to rotate without turning the worm gear shaft. The replacement mechanism failed in a different place; it had a bushing to adapt the sqare rod that runs the length of the blinds to a hexagonal through-hole in the driving gear. That bushing was made of plastic and had worn to the point that the drive gear could rotate without rotating the square rod.

The original tilt mechanism was made largely from metal components, while the replacement I had purchased was largely plastic. Examining them both, I determined that it would be more straight-forward to machine a new pully for the original mechanism than to machine a drive gear for the replacement mechanism. The original pully was made of nylon; I chose to machine a replacement pully from aluminum bar stock.

Cutting the main profile of the spool body:

1-cutting-main-profile.jpg 2-cutting-deeper.jpg

And the conical recess in the spool: 3-conical-recess.jpg

Cutting the spool off the stock: 4-cutoff-conical.jpg 5-cutoff-flat.jpg

Milled the slot for the worm gear shaft and the holes required for the threading the pull cord through: 6-milled-slot-conical.jpg 7-milled-slot-flat.jpg

Installed in the blinds: 8-installed.jpg 9-installed-closeup.jpg

This has held up well over the past 8 months, and it was gratifying to be able to repair something when replacement parts were no longer available.

Building an electronics organizer

The number of tablets, laptops, phones, ... let's just say "electronic devices" around the house has increased noticeably over the years, and finding that we had them haphazardly piled upon the end-table, ready to cascade off into a pile of mutual destruction, I decided we needed a mechanism for organizing them and defining an official location where they belong.

Design:

Given that I wanted room for six devices up to 1" thick, that meant 7 vertical boards, 3/4" thick each, yielding a base board 11-1/4" long. Allowing 1/4" for kerf leaves me with some room for error, so that leaves 60.5" of material from which to cut 7 uprights. That will mean 6 kerfs, giving me 59" of remaining material to allocate among the uprights. Making the upgrights equal lengths gives a height a little under 8.5". Rather than doing that, I opted to make the upgrights 9", 8.5", 8", 8", 8", 8.5", and 9" tall, giving a more interesting shape to the final product and giving nice "round" numbers for the lengths.

Materials:

  • 1x 6-foot, 1x8 poplar lumber
  • 14x 1-1/4" pocket-hole screws
  • wood stain

Tools:

  • pocket-hole jig
  • drill motor
  • tablesaw with fence and miter gauge
  • mitersaw

(Ideally, anyway; I actually made do with the tablesaw, but some of the cuts suffered for it.)

  • bench sander
  • several bar clamps with rubber feet

Cutting:

I cut the 11-1/4" base, two 9" uprights, two 8.5" uprights, and three 8" uprights. Then drilled two pocket-holes in each of the uprights, but _not_ in the base. I slightly rounded the corners of the wood on the bench sander, and touched up a couple of the cut faces where I had accidentally wiggled the board and gotten a less-than-perfect cut.

cut-and-drilled.jpg

Staining:

With a brush, I applied stain to one side of each of the pieces, wiped them down with a rag, applied stain to the edges (except the bottom edges of the uprights since those would not be visible) and wiped them down again, and then applied stain to the reverse side of each upright and wiped them all down. Then allowed them to dry overnight.

stained.jpg

Assembly:

The gaps between the uprights are too narrow to get a drill motor between them, so all the uprights have the pockethole screws facing the same direction, and I screwed them to the base in order from one end. Using the table saw as a clamping structure worked out very well for keeping the uprights aligned with the base and at right angles to it.

assembly-upright-3.jpg

assembled.jpg

Installed:

And here it is placed on a deep shelf with powerstrips behind it for the wall-warts and chargers.

installed.jpg

All-in-all, this worked out very well for what I was attempting to solve, and it came together with a lot less time invested than I had expected.

More fun with the bash prompt

A few years ago, I posted some fun Bash prompt tools, part of which was adding emoticons to the prompt based on the previous command's exit code. I figured it was time to revisit that bit of fun with a couple of enhancements.

First, a bit of code cleanup so color choices are more obvious, and add faces for SIGILL and SIGKILL.

#!/bin/bash
# source this
function prompt_smile () {
    local retval=$?
    local red=196
    local yellow=226
    local green=46
    local darkgreen=28
    if [ $retval -eq 0 ]; then
        color=$green
        face=":)"
    elif [ $retval -eq 1 ]; then
        color=$red
        face=":("
    elif [ $retval -eq 130 ]; then # INT
        color=$yellow
        face=":|"
    elif [ $retval -eq 132 ]; then # ILL
        color=$darkgreen
        face=":-&"
    elif [ $retval -eq 137 ]; then # KILL
        color=$red
        face="X_X"
    elif [ $retval -eq 139 ]; then # SEGV
        color=$red
        face=">_<"
    elif [ $retval -eq 143 ]; then # TERM
        color=$red
        face="x_x"
    else
        color=$red
        face="O_o"
    fi
    echo -e "\001$(tput setaf $color; tput bold)\002$face\001$(tput sgr0)\002"
    return $retval # preserve the value of $?
}
PS1="$PS1\$(prompt_smile) "

Download

When sourced into your shell with . promptsmile.sh, you get results like this:

bash-4.4$ . promptsmile.sh
bash-4.4$ :) false
bash-4.4$ :( true
bash-4.4$ :) sleep 60 & X=$!; (sleep 1; kill -INT $X) & fg %1
[1] 26699
[2] 26700
sleep 60

[2]+  Done                    ( sleep 1; kill -INT $X )
bash-4.4$ :| sleep 60 & X=$!; (sleep 1; kill -ILL $X) & fg %1
[1] 26709
[2] 26710
sleep 60
Illegal instruction (core dumped)
[2]   Done                    ( sleep 1; kill -ILL $X )
bash-4.4$ :-& sleep 60 & X=$!; (sleep 1; kill -KILL $X) & fg %1
[1] 26776
[2] 26777
sleep 60
Killed
[2]+  Done                    ( sleep 1; kill -KILL $X )
bash-4.4$ X_X sleep 60 & X=$!; (sleep 1; kill -SEGV $X) & fg %1
[1] 26788
[2] 26789
sleep 60
Segmentation fault (core dumped)
[2]   Done                    ( sleep 1; kill -SEGV $X )
bash-4.4$ >_< sleep 60 & X=$!; (sleep 1; kill -TERM $X) & fg %1
[1] 26852
[2] 26853
sleep 60
Terminated
[2]+  Done                    ( sleep 1; kill -TERM $X )
bash-4.4$ x_x (exit 4)
bash-4.4$ O_o true
bash-4.4$ :) exit

One bit of feedback I received was that the use of :) vs x_x meant that command prompts would shift by a character, and it would be better to have all the emoticons be of the same width. So if you prefer your faces all the same width, promptsmile-3wide.sh gives you more consistent line lengths:

#!/bin/bash
# source this
function prompt_smile () {
    local retval=$?
    local red=196
    local yellow=226
    local green=46
    local darkgreen=28
    if [ $retval -eq 0 ]; then
        color=$green
        face=":-)"
    elif [ $retval -eq 1 ]; then
        color=$red
        face=":-("
    elif [ $retval -eq 130 ]; then # INT
        color=$yellow
        face=":-|"
    elif [ $retval -eq 132 ]; then # ILL
        color=$darkgreen
        face=":-&"
    elif [ $retval -eq 137 ]; then # KILL
        color=$red
        face="X_X"
    elif [ $retval -eq 139 ]; then # SEGV
        color=$red
        face=">_<"
    elif [ $retval -eq 143 ]; then # TERM
        color=$red
        face="x_x"
    else
        color=$red
        face="O_o"
    fi
    echo -e "\001$(tput setaf $color; tput bold)\002$face\001$(tput sgr0)\002"
    return $retval # preserve the value of $?
}
PS1="$PS1\$(prompt_smile) "

Download

Which looks like this:

bash-4.4$ . promptsmile-3wide.sh
bash-4.4$ :-) false
bash-4.4$ :-( true
bash-4.4$ :-) sleep 60 & X=$!; (sleep 1; kill -INT $X) & fg %1
[1] 26914
[2] 26915
sleep 60

[2]+  Done                    ( sleep 1; kill -INT $X )
bash-4.4$ :-| sleep 60 & X=$!; (sleep 1; kill -ILL $X) & fg %1
[1] 26925
[2] 26926
sleep 60
Illegal instruction (core dumped)
[2]   Done                    ( sleep 1; kill -ILL $X )
bash-4.4$ :-& sleep 60 & X=$!; (sleep 1; kill -KILL $X) & fg %1
[1] 26991
[2] 26992
sleep 60
Killed
[2]+  Done                    ( sleep 1; kill -KILL $X )
bash-4.4$ X_X sleep 60 & X=$!; (sleep 1; kill -SEGV $X) & fg %1
[1] 27001
[2] 27002
sleep 60
Segmentation fault (core dumped)
[2]   Done                    ( sleep 1; kill -SEGV $X )
bash-4.4$ >_< sleep 60 & X=$!; (sleep 1; kill -TERM $X) & fg %1
[1] 27065
[2] 27066
sleep 60
Terminated
[2]+  Done                    ( sleep 1; kill -TERM $X )
bash-4.4$ x_x (exit 4)
bash-4.4$ O_o true
bash-4.4$ :-) exit

For that old-school style, the text-based emoticons work well, but systems that support emojis are becoming rather common-place, so we can use UTF-8 to get little emotional faces in our prompts:

#!/bin/bash
# source this
function prompt_emoji () {
    local retval=$?
    local red=196
    local yellow=226
    local green=46
    local darkgreen=28
    if [ $retval -eq 0 ]; then
        color=$yellow
        face=$'\360\237\230\200' # :D
    elif [ $retval -eq 1 ]; then
        color=$yellow
        face=$'\360\237\230\246' # :(
    elif [ $retval -eq 130 ]; then # INT
        color=$yellow
        face=$'\360\237\230\220' # :|
    elif [ $retval -eq 132 ]; then # ILL
        color=$darkgreen
        #face=$'\360\237\244\242' # nauseated # get a rectangle in Konsole
        face=$'\360\237\230\223' # cold sweat face
    elif [ $retval -eq 137 ]; then # KILL
        color=$yellow
        face=$'\360\237\230\265' # x_x
    elif [ $retval -eq 139 ]; then # SEGV
        #color=$yellow
        #face=$'\360\237\244\250' # Face with one eyebrow raised # get a rectangle in Konsole
        color=$red
        face=$'\360\237\230\240' # Angry face
    elif [ $retval -eq 143 ]; then # TERM
        color=$yellow
        face=$'\360\237\230\243' # >_<
    else
        color=$yellow
        face=$'\360\237\230\245' # ;(
    fi
    echo -e "\001$(tput setaf $color; tput bold)\002$face\001$(tput sgr0)\002"
    return $retval # preserve the value of $?
}
PS1="$PS1\$(prompt_emoji) "

Download

Which will give something maybe like this. The way the faces are rendered will depend on your terminal. For Konsole, these are simple line art; for Gnome-terminal some match Konsole, others have a more blob-like shape; and here they're rendered by your browser.

bash-4.4$ . promptemoji.sh
bash-4.4$ 😀 false
bash-4.4$ 😦 true
bash-4.4$ 😀 sleep 60 & X=$!; (sleep 1; kill -INT $X) & fg %1
[1] 27143
[2] 27144
sleep 60

[2]+  Done                    ( sleep 1; kill -INT $X )
bash-4.4$ 😐 sleep 60 & X=$!; (sleep 1; kill -ILL $X) & fg %1
[1] 27154
[2] 27155
sleep 60
Illegal instruction (core dumped)
[2]   Done                    ( sleep 1; kill -ILL $X )
bash-4.4$ 😓 sleep 60 & X=$!; (sleep 1; kill -KILL $X) & fg %1
[1] 27220
[2] 27221
sleep 60
Killed
[2]+  Done                    ( sleep 1; kill -KILL $X )
bash-4.4$ 😵 sleep 60 & X=$!; (sleep 1; kill -SEGV $X) & fg %1
[1] 27232
[2] 27233
sleep 60
Segmentation fault (core dumped)
[2]   Done                    ( sleep 1; kill -SEGV $X )
bash-4.4$ 😠 sleep 60 & X=$!; (sleep 1; kill -TERM $X) & fg %1
[1] 27295
[2] 27296
sleep 60
Terminated
[2]+  Done                    ( sleep 1; kill -TERM $X )
bash-4.4$ 😣 (exit 4)
bash-4.4$ 😥 true
bash-4.4$ 😀 exit

Beyond that, you'll find that your terminal may render a different subset of emojis than what mine does. I found a useful site for finding emojis with octal UTF-8 which makes it easy to update promptemoji.sh with something that suits your particular set of software.

And for ANSI colors, you may find this reference handy.

Go then, and liven up your own bash prompts, even more!

LDraw Parts Library 2019-02 - Packaged for Linux

LDraw.org maintains a library of Lego part models upon which a number of related tools such as LeoCAD, LDView and LPub rely.

I packaged the 2019-02 parts library for Fedora 29 to install to /usr/share/ldraw; it should be straight-forward to adapt to other distributions.

The *.noarch.rpm files are the ones to install, and the .src.rpm contains everything so it can be rebuilt for another rpm-based distribution.

ldraw_parts-201902-ec1.fc29.src.rpm

ldraw_parts-201902-ec1.fc29.noarch.rpm
ldraw_parts-creativecommons-201902-ec1.fc29.noarch.rpm
ldraw_parts-models-201902-ec1.fc29.noarch.rpm

LeoCAD 19.07.1 - Packaged for Linux

LeoCAD is a CAD application for building digital models with Lego-compatible parts drawn from the LDraw parts library.

I packaged (as an rpm) the 19.07.1 release of LeoCAD for Fedora 29. This package requires the LDraw parts library package.

Install the binary rpm. The source rpm contains the files to allow you to rebuild the packge for another distribution.

leocad-19.07.1-1ec1.fc29.x86_64.rpm

leocad-19.07.1-1ec1.fc29.src.rpm

Grid-based Tiling Window Management

Many years ago, a coworker of mine showed me Window's "quick tiling" feature, where you would press Window-LeftArrow or Window-RightArrow to snap the current window to the left or right half of the screen. I then found that KDE on Linux had that same feature and the ability to snap to the upper-left, lower-left, upper-right, or lower-right quarter of the screen. I assigned those actions to the Meta-Home, Meta-End, Meta-PgUp, and Meta-PgDn shortcuts. (I'm going to use "Meta" as a generic term to mean the modifier key that on Windows machines has a Windows logo, on Linux machines has a Ubuntu or Tux logo, and Macs call "command".) Being able to arrange windows on screen quickly and neatly with keyboard shortcuts worked extremely well and quickly became a capability central to how I work.

Then I bought a 4K monitor.

With a 4K monitor, I could still arrange windows in the same way, but now I had 4 times the number of pixels. There was room on the screen to have a lot more windows that I could see at the same time and remain readable. I wanted a 4x4 grid on the screen, with the ability to move windows around on that grid, but also to resize windows to use multiple cells within that grid.

Further complicating matters is the fact that I use that 4K monitor along with the laptop's !FullHD screen which is 1920x1080. Dividing that screen into a 4x4 grid would be awkward; I wanted to retain a 2x2 grid for that screen, and keep a consistent mechanism for moving windows around on that screen and across screens.

KDE (Linux)

Unfortunately, KDE does not have features to support such a setup. So I went looking for a programatic way to control window size and placement on KDE/X11. I found three commandline tools that among them offered primitives I could build upon: xdotool, wmctrl, and xprop.

My solution was to write a Python program which took two arguments: a command and a direction.

The commands were 'move', 'grow', and 'shrink', and the directions 'left', 'right', 'up', and 'down'. And one additional command 'snap' with the location 'here' to snap the window to the nearest matching grid cells. The program would identify the currently active window, determine which grid cell was a best match for the action, and execute the appropriate xdotool commands. Then I associated keyboard shortcuts with those commands. Meta-Arrow keys for moving, Meta-Ctrl-Arrow keys to grow the window by a cell in the given direction, Meta-Shift-Arrow to shrink the window by a cell from the given direction, and Meta-Enter to snap to the closest cell.

system-settings-config.png

Conceptually, that's not all that complicated to implement, but in practice:

Window geometry has to be adjusted for window decorations. But there appears to be a bug with setting the position of a window. The window coordinates used by the underlying tools for setting and getting the geometries do not include the frame, except for setting the position of the window, on windows that have a 'client' of the machine name instead of N/A. Getting the position, getting the size, and setting the size, all use the non-frame values. Windows with a client of N/A use the non-frame values for everything. A border width by title bar height offset error for only some of the windows proved to be a vexing bug to track down.

The space on a secondary monitor where the taskbar would be is also special, even if there is no task bar on that monitor; attempting to move a window into that space causes the window to shift up out of that space, so there remains an unused border on the bottom of the screen. Annoying, but I have found no alternative.

Move operations are not instantaneous, so setting a location and immediately querying it will yield the old coordinates for a short period.

A window which is maximized does not respond to the resize and move commands (and attempting it will cause xdotool to hang for 15 seconds), so that has to be detected and unmaximized.

A window which has been "Quick Tiled" using KDE's native quick-tiling feature acts like a maximized window, but does not set the maximized vert or maximized horz state flags, so cannot be detected with xprop, and to get it out of the KDE quick tiled state, it must be maximized and then unmaximized. So attempting to move a KDE quick tiled window leads to a 15 second pause, then the window maximizing briefly, and then resizing to the desired size. In practice, this is not much of an issue since my tool has completely replaced my use of KDE's quick-tiling.

OS X

I recently whined to a friend about not having the same window management setup on OS X; and he pointed me in the direction of a rather intriguing open source tool called Hammerspoon which lets you write Lua code to automate tasks in OS X and can assign keyboard shortcuts to those actions. That has a grid module that offers the necessary primitives to accomplish the same goal.

After installing Hammerspoon, launching it, and enabling Accessibility for Hammerspoon (so that the OS will let it control application windows), use init.lua as your ~/.hammerspoon/init.lua and reload the Hammerspoon config. This will set up the same set of keyboard shortcuts for moving application windows around as described in the KDE (Linux) section. For those who use OS X as their primary system, that set of shortcuts are going to conflict with (and therefore override) many of the standard keyboard shortcuts. Changing the keyboard shortcuts to add the Option key as part of the set of modifiers for all of the shortcuts should avoid those collisions at the cost of either needing another finger in the chord or putting a finger between the Option and Command keys to hit them together with one finger.

I was pleasantly surprised with how easily I could implement this approach using Hammerspoon.

Demo

Simple demo of running this on KDE:

(And that beautiful background is a high resolution photo by a friend and colleague, Sai Rupanagudi.)

LDraw Parts Library 2019-01 - Packaged for Linux

LDraw.org maintains a library of Lego part models upon which a number of related tools such as LeoCAD, LDView and LPub rely.

I packaged the 2019-01 parts library for Fedora 29 to install to /usr/share/ldraw; it should be straight-forward to adapt to other distributions.

The *.noarch.rpm files are the ones to install, and the .src.rpm contains everything so it can be rebuilt for another rpm-based distribution.

ldraw_parts-201901-ec1.fc29.src.rpm

ldraw_parts-201901-ec1.fc29.noarch.rpm
ldraw_parts-creativecommons-201901-ec1.fc29.noarch.rpm
ldraw_parts-models-201901-ec1.fc29.noarch.rpm

LeoCAD 18.02 - Packaged for Linux

LeoCAD is a CAD application for building digital models with Lego-compatible parts drawn from the LDraw parts library.

I packaged the 18.02 release of LeoCAD for Fedora 29. This package requires the LDraw parts library package.

Install the binary rpm. The source rpm contains the files to allow you to rebuild the packge for another distribution.

leocad-18.02-1ec1.fc29.x86_64.rpm

leocad-18.02-1ec1.fc29.src.rpm