Contents

Editorial



May 2019

I haven't released a newsletter since January 2019. In that newsletter I explained that future newsletters may be rather ad hoc and so they have been. I made requests on many occasions for readers to submit articles as I no longer have the time or interest to produce a newsletter each month. I will only release a newsletter when I consider I have enough content.

Because of my extended break, a few interesting things have occurred in Puppy Land while I was away.

Fatdog64-800 Final was released on 28 Feb 2019.

TazPuppy has reached Beta 25.

Puli 64 bit released on 16 Feb 2019.

Barry has progressed EasyOS and stopped working on a couple of other projects.

If there are other new or updated Puppyish distros available, please let me know so I can include them. A review would be welcomed.

You might have noticed the entertainment section is missing. Greengeek is taking a break as well.

This month I rekindled an old relationship with Midnight Commander. It is such a good File Manager and the additional tools like ftp and sftp are
also brilliant. In the past I barely touched the surface of this great little application but now I'm having a closer look. Although it's a text based application
it works great with the mouse or keyboard.

Best Regards

smokey01

Distros

The Puppy Linux Discussion Forum is the main source for a lot of the information repeated here. Where appropriate, links will be provided so you can read first hand about the distribution development. This section will likely just provide highlights as a starting point.

Fatdog64-800 - The Fatdog team.
Tazpuppy - mistfire.
Puli - gjuhasz.
EasyOS - Barry Kauler
Precise-light
Fatdog64-800

Fatdog64-800 was released on 28 Feb 2019.

After nine months in the making with about 4 months testing (both internal and public), Fatdog Team is pleased to announce the general availability of Fatdog64 800 Final on 28 Feb 2019.

This is a new series of Fatdog, based on LFS 8.2, replacing the 700 series started five years ago with LFS 7.5.
It is the same Fatdog that you know and love, only better.
It comes with updated packages and improved applications.
Tazpuppy B25

TazPuppy B25 was released on 24 March 2019.

TazPuppy is basically a Puppyfied slitaz. It's a full featured compact distro.

The Beta 25 distro is 99M.
Puli 64 bit

Puli 64 bit was released on 16 Feb 2019.

Puli is a member of the Puppy Linux family: a high security, "kiosk" flavour of 666philb's Tahrpup 6.0.6 CE (32-bit, aka Puli 6) and Xenialpup64 CE 7.5 (64-bit, aka Puli 7), intended to boot from a USB pendrive and run safely even if the boot device is unplugged.

Announcement and changelog for the 32-bit version: here, for the 64-bit version: here.
EasyOS

Written by smokey01

It appears Barry Kauler has been making a few changes lately.

His latest masterpiece, EasyOS now has its own website at: https://easyos.org/

He has also created a dedicated forum for EasyOS here: https://easyos.org/forum/

Having recently discovered the EasyOS forum I've just noticed discussion for EasyOS at the above address is now closed and will continue at:
http://murga-linux.com/puppy/viewtopic.php?t=109958

Reading too many forums can be a bit tiresome.

Recently Barry also closed the Quirky project and OpenEmbedded.

Read all about it here.

If you've been reading Barry's blogs you may have noticed he is turning into a Grey Nomad, if not already there. I must admit it's a pretty interesting life. Unlike the light camping that Barry prefers I tend to do Glamping, well that's the way she who must be obeyed likes it. We have a 22 foot van with all the bells and whistles but unfortunately it has not seen the road for a couple of years as we have my elderly father living with us. It makes it very difficult to get away.

Read Barry's Nomad site here.

Maybe our paths will cross in the future, fingers crossed.
Precise-light

Precise-light was released on 06 April 2019 by jrb.



Hopefully this will be of some use on your older hardware. Good Luck.
Software

Calcurse a text based personal organiser - smokey01
Midnight Commander a text based File Manager - smokey01
Calcurse

Written by smokey01

After reading a post by forum member rufwoof in the Fatdog64-800 thread, I noticed he mentioned a little text based application called calcurse. I must say it sounded quite interesting so I had to have a look.

This is the calcurse website so you can read more about it here.



Click on the Download button to download the source.

Compiling instruction here.
Midnight Commander

Written by smokey01

Midnight Commander (mc) is a brilliant text based file manager.

I really didn't appreciate how good it was until I installed it on my VPS.

It makes managing your website via SSH so easy and it's really fast. It may not be as pretty as some Graphical File Managers
but when operating from the CLI this is a must have.

I have always used Filezilla in the past but with the inbuilt ftp and sftp protocols I no longer need it.



A good mc tutorial


Tutorials

Audio Recording - Terry Schuster
Password protect a WEB Directory - smokey01
Web Tutorial - smokey01
Audio Recording

Audio Recording Using a Dedicated Puppy Linux OS by Terry Schuster

For many years a hobby of mine has been the digitization of audio from Vinyl LPs, cassettes and CDs. While Windows is an acceptable OS for audio recording, processing of large files is relatively slow and inefficient, well-functioning freeware is not as easily obtained as one might expect. Almost two years ago I took a serious look at Linux on the basis of available freeware and in the process discovered Puppy Linux which has become my OS of choice for everyday computing tasks.

Puppy Linux is ideally suited for stand-alone projects as it can be easily installed and modified for specific tasks. There already exist a number of Puppy Linux derivatives specifically tailored for audio, including Puppy Studio, which also has Pulse Audio installed. However, I went for a simple approach which I could modify to suit my needs.

The advantages using any variant of Puppy Linux in an audio situation include:
• Fast processing speeds, especially of large files
• Fast saving of files to hard drive
• A host of Linux audio freeware applications
• Windows software running under Wine usually runs much faster
• Specific projects can be given their own savefile/savefolder

For almost two years I have been using Tahr 6.0.5 as the base for audio recording of vinyl LP’s and ripping of CD’s to compressed format. While now a bit dated, Tahr 6.0.5 is a reliable workhorse, very stable, and popular - which means that there is a lot of information on the forums if an issue arises. I decided to use a single OS for all my recording because any changes are not saved at the and of the session and a pristine environment is presented at every every boot, apart from any deliberate modifications. I also chose to do a full install on a 16Gb USB 2.0 flash drive for portability, as described about this in the September 2017 edition of the PLN, but any installation of Puppy Linux will probably suffice. The host computer is rather ancient (2002) 32 bit clunker, having only 2Gb RAM, but dual processors. I could upgrade the RAM to 4Gb, but seem to manage without it. I save all recorded sound files to the resident hard drive as wav and/or MP3 files.

Over the years I have found that the biggest single biggest issue with sound recording is the quality of the sound card on board the computer. A valuable investment has been a Soundblaster USB external sound card. While some of the accompanying software will not run in Wine, the USB sound card will still operate but with less control over input volume, which is not a substantial issue provided there is an external volume control – eg in the amplifier output.

My setup is fairly simple. For the recording of audio ( eg cassette player/turntable ) the original sound source is fed in to my 1980’s amplifier and the output from the headphone socket fed into the USB sound card. There is a particular issue to overcome in getting the audio recognized by the hardware, and a configuration file needs to be edited. The process as listed below is based on details found at the Coderwall site listed in the references.

1) Click on the Multiple Sound Card Wizard, and select the sound card which is to be the default device.

2) NOTE the Card / Device settings - in my case it is Card 2: Pro SB X-Fi, Device 0.

3) Using Leafpad or Geany open the alsa.config file, found in /user/share/alsa.
Add/Change the following pairs of lines as follows:
defaults.ctl.card 2
defaults.ctl.device 0

defaults.pcm.card 2
defaults.pcm.device 0

defaults.rawmidi.card 2
defaults.rawmidi.device 0

defaults.hwdep.card 2
defaults.hwdep.device 0

defaults.timer.card 2
defaults.timer.device 0
Save the changes by clicking on the SAVE button on the top menu.

4) You also need to check that the configuration is correct for the Hardware, by opening up the configuration files for Retrovol and selecting Config Window. Ensure the numbered sound card matches what was noted in step 2: eg for Card 2 it would look like hw:2. Click on Apply.

5) Open up mhWaveEdit, which will be the recording application.
Go to Edit → Preferences → Sound Settings tab
Keep ALSA as the sound software.
Click on Auto detect Driver option, and Event Driven I/O
Click on the Settings tab. Ensure the default settings are enabled, and click OK.

Hopefully the sound input/output will then be available through the external Sound Card.

Anybody intending to record vinyl LPs needs to be aware that cleaning is an essential task in order to remove dust and stuck-on materials, both of which can spoil a recording by causing the stylus to jump tracks. I use a 1/3 mixture of Isopropyl Alcohol with 2/3 distilled water plus a drop of detergent to clean the surface, applied with a paint pad. To rinse the surfaces I use distilled water laced with a wetting agent such as Ilford ILFOTOL.

To record audio I use mhWaveEdit, which is OOTB on the OS. There are a number of features which make this an excellent go-to recording application:
• A simple, uncluttered GUI
• Precise VU metering which is indispensable for digital audio recording
• Blisteringly fast save/load times
• Ability to record for a given time
• A good suite of editing features





During recording I try to keep the peak level well below the maximum permitted value to avoid clipping of the wave signal which leads to audibly distorted sound. As part of the editing process the sound levels are adjusted or normalized. A trial recording is always useful to set the level, although most LPs are recorded at similar levels.

Once the original wave file is recorded and saved, I use Gnome Wave Cleaner to start the editing process. It is available in the Puppy Package manager. This apparently little known application runs best where Pulse Audio is operational, and will not output sound on my current OS. However, despite the ordinary GUI and some non-operational features it is a sophisticated application and has a number of excellent functions which make it very good for post-recording processing. Some of these features include:

• Noise reduction. By selecting a section of “noise” near the start or end of the recording, noise reduction based on that profile can be applied a number of times in succession (if rerquired) to reduce noise to an acceptable level.

• Track Splitting. Gaps between recorded tracks can be marked manually or automatically (when it works!) These tracks can then be split with one or two clicks and saved as individual files - a process which happens in a second or two.

• Click Reduction. Individual clicks can largely be removed by a simple application. Globally applied click reduction to a track or whole side of an LP recording can also be achieved and gives quite reasonable results.



There are other features in this application that can be utilized, although the settings are not intuitive and reflect the sophisticated nature of what the software is trying to achieve. Despite this, it is an excellent fit for the purposes mentioned above.

Once the tracks are split, they can be individually edited to remove extraneous sections at the start and end. I use Creative software for this process. Creative’s wave editing application Creative Studio runs very well under Wine. While the older sound cards are no longer produced, dated software versions such as Creative Studio_7 are now available online as an executable file WAVESTD_PCAPP_LB_7_1. See References for the download site.




While other freeware such as Audacity is often quoted as THE go-to editing freeware, I find that the GUI is very cluttered and has too many features for basic editing, which is why I use Creative Studio. It has a simple GUI, clear, precise display of the wave pattern, and runs very fast under Wine. Most importantly, it has a number of features not always available in other editors, or not as easy to implement. For example, to manually repair a click on one track only, I often mute the affected section on the track, copy a similar length piece of waveform from nearby on the same or other track, and paste that patch into the muted section.

Due to a relatively low amount of RAM onboard, I also need to occasionally flush the memory, especially when large (250Mb) files are being edited, although the use of a swapfile would be helpful. CleanRam is a dedicated .pet with a colourful GUI which does the job well. I prefer to use a Bash script which is engaged with a single click. To place the shortcut on the desktop simply drag the script file to the desktop using ROX.

#!/bin/sh
# simple tool for puppy linux to clean caches
# Joe Arose aka big_bass
gxmessage "
before flush
`free -m`
--------------------------------------------------------------------
`sync ; echo 3 > /proc/sys/vm/drop_caches`
after flush
--------------------------------------------------------------------
`free -m`
"
Once the wave files are edited, I also run another restoration program (Steinberg Clean) under Wine to remove other noise and crackles and add other effects. This is not a freeware product and may no longer be available, but is another example of a Windows program that works perfectly in Wine.

After all wave files are processed, I name each file with the Artist/Album and track name, but also set the number of the track earlier in the title which will help ordering the files when they are played.
A typical label would be Bach Organ Works V5_01_Prelude in E.wav

One issue I face is the processing of mono records which, obviously have the same audio signal in both channels. An artificial stereo effect can be generated by introducing a phase delay of 10-30 milliseconds between the two channels, adding a small amount of echo as desired, and then, if available, use a stereo spread feature found in some audio editing programs to complete the effect which is most useful when listening to the music with headphones.

The wave files produced are large in size and hardly portable. To convert the wave files to MP3s, I used CDExtract in the past, which works quite well under Wine and provides an excellent number of features. For convenience I use LAME codec and 160Kbps, although 190Kbps would give even higher quality. In recent times I have been using a Bash script to do the conversion, which is a combination of a couple of sources. It appears that FFMPEG is depreciated in Tahr 6.0.5, and ACONV, a derivative of the latter does the same job. The script file is loaded into a convenient directory and edited to point to the directory which contains the wave files. ALL files in that directory are converted, and saved in the same directory. The script when executed, is very quick. Note, that sdb1 is the hard drive on which the files are stored in this case.

#!/bin/sh
cd /mnt/sdb1/"Pathway to/The Required/Directory"
# Batch convert of all wave files in that directory to mp3
for i in *.wav;
do
avconv -i "$i" -codec:a libmp3lame -b:a 160k "${i%.*}.mp3"
done

Should I wish to rip files from a standard audio CD, the code is modified as follows:

#!/bin/sh
# Set destination directory for Wave and subsequent MP3 files and run ripping command
cd /mnt/sdb1/"Pathway to/The Required/Directory"
cdparanoia -B # All CD tracks saved as separate .wav files in the above directory
# Wave Files are converted to MP3 in same directory
for i in *.wav;
do
avconv -i "$i" -codec:a libmp3lame -b:a 160k "${i%.*}.mp3"
done
# Wave files can be deleted as required after all conversions are complete

Once the MP3 files are processed, the ID tags need to be labelled so an MP3 player can fully display the track details. As the Artist and Album are always the same, I use a Windows program TigoTago running under Wine to add details. It has an efficient spreadsheet-like GUI, which makes labelling a very quick process, the track title being extracted from the filename. The version of Wine I use does not render the GUI perfectly, but maintains functionality.



Once compressed, the MP3 files can be loaded on to portable devices or streamed over a local network using MPD or similar.

In certain situations it is more practical to record to MP3 on the fly, such as a high quality cassette tape recording. The resulting files still need to be edited in some way, and an excellent application which works very well under Wine is MP3DirectCut. This allows lossless editing of the MP3 file without initial conversion to a wave file. It is possible to do fadein/out, save sections to new files and so on. It is a unique and well-regarded application.



In conclusion, use of Puppy Linux as a dedicated OS is one of its great advantages. Frugal installations enable many instances of Puppy Linux of all varieties to run in a single USB or hard drive, each with a very small footprint. The use of a save-folder allows updates and backups to be simply and easily done. For applications which require speed and low latency – such as audio recording, it is a very effective tool.


References

Sound Card Settings - Coderwall fix: https://coderwall.com/p/k1hyga/fixing-the-sound-in-puppy-linux

CleanRam Site: http://murga-linux.com/puppy/viewtopic.php?t=109772&sid=ce79e48c5b533cf697c5fa3ea384cdd0

WaveStudio Download: http://support.creative.com/Downloads/searchdownloads.aspx?filename=WAVESTD_PCAPP_LB_7_1&ShowDetails=1

CDEX Download: https://cdex.mu/download

Bash Scripts for Ripping:
http://apknight.org/convert-cd-tracks-to-mp3-using-ffmpeg/
https://superuser.com/questions/749416/rip-cd-dvd-with-ffmpeg
https://gist.github.com/timstermatic/7384516

CDparanoia manual: https://www.xiph.org/paranoia/manual.html

TigoTago Download (up to Win8, but can work in Win10): http://tigotago.com/

Bash script by Joe Arose http://www.murga-linux.com/puppy/viewtopic.php?t=78196&sid=58b6eacb4c066fce6c1c679aa4fa5292

MP3DirectCut Down
load: https://mp3directcut.en.softonic.com/
Password a WEB Directory

Password protect a directory on a Hiawatha web site by smokey01

Recently I setup a web site for my golfing buddies so they can see their daily scores, leaderboard and the playing schedule.
I also thought it might be a good idea to protect the web site from unwanted guests.

Initially I had a bit of trouble protecting the web site so I turned to my friend jamesbond who always comes through. Thanks James.

I use Hiawatha on my Virtual Private Server (VPS) as it's a great webserver. It may not be as big or as popular as Apache but it does all I need.

Assumption: You have Hiawatha installed on your website.

In the directory that you wish to protect create a file called .hiawatha. Notice the dot/period in front of hiawatha, that makes the file invisible.
To be able to see the file, once created, you need to tell your file manager to show hidden files. In Rox Filer just click on the eye on the tool menu.

The contents of the .hiawatha file you just created is:

PasswordFile = digest:/path/to/.passwd
LoginMessage = MembersOnly


The first line provides information of the .passwd file name and its location.
There are two methods, basic and digest. Digest is more secure so we will use that. Let's place the .passwd file in the /usr/local/secret directory.

PasswordFile = digest:/usr/local/secret/.passwd

The second line: LoginMessage = MembersOnly Provides a message. This message can be anything you want and it is displayed after the Username and Password prompt.

We have indicated we have a .passwd file in /usr/local/secret/. First we need to create the secret directory and in that directory we need to create the .passwd file.
Once we have created the .passwd file we need to give it some contents. There are a couple of ways to do this:
1. User wigwam which is part of hiawatha but you will need to use ssh to do this.
2. We will do it the easy way with a website that creates the information for us.

Click here to open a password generator site. You you see the following.



In the Username box type the username you wish to use.
Similarly type your selected Password in the password box and click the create .htpasswd file button.

I typed puppy for Username and linux for the password.

After clicking the button the following should pop up:



Now copy the text in the box above into your /usr/local/secret/.passwd file.

If you wish to have more than one login account repeat this process and keep adding the results to the .passwd file.
Remember: One entry per line as it says.

I am happy with one login account so I just let everyone use the same Username and Password.

One more thing to do

We need to tell Hiawatha to use the local config file. We do this by adding the following line to the hiawatha.conf file:
UseLocalConfig = yes

I placed this line under:
#ServerId = www-data

The hiawatha.conf is normally found in /etc/hiawatha/ but if it's not try this command:

find -name hiawatha.conf

That's it.

Web Tutorial

Written by smokey01

I believe one of the best Web Site Tutorials available is w3schools.com.
It's my first port of call when looking for help.

It provides online real time examples. It allows you to change the code and immediately see the results.

If you are not aware of this site and need help building a web site, the is a great place to start.

It's nice to use a full wysiwyg html editor at times, especially when you are in a hurry, but to get minimal nice clean code I like to use a text editor.
Compiling

This is a good section to discuss how to compile software. Compiling is not everyone's cup of tea but the more people that can manage it, the longer life Puppy will have.
The hardest part of compiling is the build recipe as there are so many options. Let's include some proven recipes here.
You must have the devx loaded as this is where most of your compiling tools reside. In some cases you may also need to have the kernel sources loaded.

calcurse - smokey01
calcurse

Written by smokey01

Download the source code: https://calcurse.org/files/calcurse-4.4.0.tar.gz

Extract the source into a working directory.

Enter the working directory and open a terminal.

In the terminal type: ./configure --prefix=/usr

When it has finished type: make

Then type: make install

or

If you wish to make a .pet package type:

make DESTDIR=/root/calcurse-4.4.0 install

This will place all of the required files into a directory called calcurse-4.4.0 under /root

To make a .pet type: dir2pet calcurse-4.4.0 one level up from the calcurse directory.

Now you can distribute calcurse-4.4.0.pet to your friends.
Scripts & Code

mm_view a file viewer - MochiMoppel
mm_view_20190409

Written by MochiMoppel

mm_view is a brilliant file viewer written in bash and gtkdialog.

Copy the code below and paste it into a text editor, save it and make it executable.

#!/bin/bash
### Universal file viewer
### MochiMoppel 2019-04-09
### http://www.murga-linux.com/puppy/viewtopic.php?t=109573
{ #File locations
[[ $USER = root ]] && export TEMPDIR=/tmp/mm_view/ || export TEMPDIR="/tmp/mm_view.${USER}/"
export DUMPDIR=${TEMPDIR}dump/
export CNFGDIR=$HOME/.config/mm_view/
[[ -d $TEMPDIR ]] || mkdir -p $TEMPDIR
[[ -d $DUMPDIR ]] || mkdir -p $DUMPDIR
[[ -d $CNFGDIR ]] || mkdir -p $CNFGDIR
}
{ #Files for TEMPDIR
#*.tmp will be deleted after MMview session, other files remain alive until Puppy shutdown
export SYMLINK=${TEMPDIR}symlink.tmp # <input file> source for <edit> and <pixmap> widgets.
export MSGFILE=${TEMPDIR}msgfile.tmp # contains info text
export NB_PAGE=${TEMPDIR}nb_page.tmp # contains notebook page
export COMMAND=${TEMPDIR}command.tmp # contains command string for vCMDLINE
export TMPFILE=${TEMPDIR}tmpfile.tmp # multipurpose tmp file
export STBFILE=${TEMPDIR}stbfile.tmp # contains optional content for status bar
export HISTORY=${TEMPDIR}history.txt # contains command history
export D_TITLE=${TEMPDIR}d_title.tmp # multi_dialog: title
export D_LABEL=${TEMPDIR}d_label.tmp # multi_dialog: text label
export D_DEFLT=${TEMPDIR}d_deflt.tmp # multi_dialog: default text for entry widget
export TTPFILE=${TEMPDIR}ttpfile.tmp # contains tooltip text for TOOLTIP_DIALOG
export MD5LIST=${TEMPDIR}md5list.tmp # contains new and previous md5sum output
export FNDFILE=${TEMPDIR}fndfile.txt # contains last used search pattern of Find dialog
export FNDREGX=${TEMPDIR}fndregx.txt # regex checkbox status (Find dialog)
export FNDCASE=${TEMPDIR}fndcase.txt # case checkbox status (Find dialog)
export FNDWORD=${TEMPDIR}fndword.txt # word checkbox status (Find dialog)
export FNDMARK=${TEMPDIR}fndmark.txt # Do not extract checkbox status (Find dialog)
export ICONMMV=${TEMPDIR}iconmmv.svg # icon for titlebar and tray
export ICOWRAP=${TEMPDIR}icowrap.svg # line wrap icon
export ICOVIEW=${TEMPDIR}icoview.svg # instant view icon
export ICONHEX=${TEMPDIR}iconhex.svg # hexdump icon
}
{ #Files for CNFGDIR
export LASTDIR=${CNFGDIR}lastdir # contains last accessed directory
export LAST_WH=${CNFGDIR}last_wh # contains last width height of window
export BOXMODE=${CNFGDIR}boxmode # vertical layout flag
}
{ #Startup folder
#Priorities: 1) Passed argument 2) Last used folder 3) Default '/'
if [[ -e $1 ]];then
[[ -d $1 ]] && DEFAULT_DIRECTORY=$1 || DEFAULT_DIRECTORY=${1%/*}
else [[ -s $LASTDIR ]] && DEFAULT_DIRECTORY=$(< $LASTDIR)
fi
[[ -d $DEFAULT_DIRECTORY ]] || DEFAULT_DIRECTORY=/
}
{ #Preferences
[[ -f $BOXMODE ]] && LAYOUT_V=true BOX=v SEP=h || LAYOUT_V=false BOX=h SEP=v # orientation (horizontal or vertical)
}
{ #Miscellaneous variables
export BR=$'&#013;' # new line in pango text
export LF=$'\n'
export TB=$'\t'
export S7='\xe2\x80\x87' #FIGURE SPACE ( )
export S8='\xe2\x80\x88' #PUNCTUATION SPACE ( )
export LINE20=$'\n────────────────────\n'
export LINE40=$'\n────────────────────────────────────────\n'
export APP_PATH=$(realpath "$0")
export SENDTOPATH="/root/.config/rox.sourceforge.net/SendTo/" # Contains "Open With" actions. Trailing slash mandatory.
export HEXDUMP_MAXBYTES=10000 #Max no. of bytes displayed as file header/footer
export HEXDUMP_VIEWER=leafpad #external program to display complete hexdump
export THRESHOLD=30 #clickpress time lag in 10/sec

}
{ #Screen dimension
[[ $(xwininfo -root) =~ Width:\ ([0-9]*).*Height:\ ([0-9]*) ]]
export SCREEN_W=${BASH_REMATCH[1]}
export SCREEN_H=${BASH_REMATCH[2]}
}
{ #Window dimension
[[ -s $LAST_WH ]] && read DEFAULT_WIDTH DEFAULT_HIGHT < $LAST_WH
((DEFAULT_WIDTH)) || DEFAULT_WIDTH=1000
((DEFAULT_HIGHT)) || DEFAULT_HIGHT=500
}
{ #Window content size
CHOOSER_WIDTH=500 # Effective only in horizontal layout (default 500)
CHOOSER_HIGHT=200 # Effective only in vertical layout (default 200)
MENUBAR_HIGHT=25 # Should not be set to 0 (disables shortcuts). Value 1 hides mbar but still allows access via F10 (default 25)
WINDOW_MARGIN=0 # Inner margin of window (default 0)
WIDGETSPACING=3 # Spaces between menu - chooser&viewer - statusbar (default 3)
CENTERSPACING=0 # Space between chooser - viewer (default 0)
L_EDIT_MARGIN=5 # Left margin of the text viewer pane (default 5)
STATUS_MARGIN=5 # Margin around bottom box containing statusbar & close button (default 5)
X_AXIS_ADJUST=2 # Compensates for width of separator. Increase value to reduce width of scaled images (default 2)
Y_AXIS_ADJUST=47 # Compensates for height of status bar, image page text and separator. Increase value to reduce height of scaled images(default 47)
}
{ #Viewer pane dimension
if [[ $LAYOUT_V == true ]] ;then
VIEWER_W=$((DEFAULT_WIDTH - WINDOW_MARGIN *2))
VIEWER_H=$((DEFAULT_HIGHT - Y_AXIS_ADJUST - MENUBAR_HIGHT - CHOOSER_HIGHT - WINDOW_MARGIN - ( CENTERSPACING + WIDGETSPACING + STATUS_MARGIN) * 2 ))
else
VIEWER_W=$((DEFAULT_WIDTH - X_AXIS_ADJUST - CHOOSER_WIDTH - (WINDOW_MARGIN + CENTERSPACING) * 2))
VIEWER_H=$((DEFAULT_HIGHT - Y_AXIS_ADJUST - MENUBAR_HIGHT - (WINDOW_MARGIN + WIDGETSPACING + STATUS_MARGIN) * 2))
fi
export VIEWER_W VIEWER_H
}
{ #Utilities
PROBE=$(type -p ffprobe) || { PROBE=$(type -p avprobe) || PROBE=false ;} ; export PROBE
PLAY=$(type -p ffplay) || { PLAY=$(type -p avplay) || PLAY=false ;} ; export PLAY
CLIP=$(type -p xclip) || { CLIP=$(type -p xsel) || CLIP=false ;} ; export CLIP
WMCTRL=$(type -p wmctrl) || WMCTRL=false ; export WMCTRL
}
{ #File initialization
ln -fsn /dev/null $SYMLINK
echo 0 > $NB_PAGE
echo > $TMPFILE
echo -n > $STBFILE
echo -n > $COMMAND
}
{ #Icons
RNDCOLOR=$(printf %x $RANDOM$RANDOM$RANDOM);RNDCOLOR=${RNDCOLOR//[0-7]};RNDCOLOR=${RNDCOLOR::3}
echo '<svg width="48" height="48" viewBox="0 0 100 100">
<style type="text/css" >
* {fill:#fff; stroke:#000;stroke-width:6}
polyline {fill:none;stroke-linecap:round;}
circle {fill:#'$RNDCOLOR'}
</style>
<!-- body,glasses,mouth,hair -->
<path d="M-2,100 C0,-10 100,-10 102,100"/>
<circle cx="27" cy="50" r="20"/>
<circle cx="73" cy="50" r="20"/>
<polyline points="65,80 70,80"/>
<polyline points="40,5 50,15 70,10 60,17"/>
</svg>' > $ICONMMV

export SVGWRAP_1='99,0 0,22 -99,0 m' # Wrap off
export SVGWRAP_2='69,0 0,22 -69,0' # Wrap on
echo '<svg width="20" height="20" viewBox="0 0 100 100" >
<style type="text/css">* {fill:#fff;stroke-width:2;stroke:#000}path{fill:none;stroke-width:6;stroke:#222;stroke-linecap:round;stroke-linejoin:round}</style>
<rect height="100" width="100"/>
<path d="m 16,29
'"$SVGWRAP_1"'
0,23 42,0"/>
</svg>' > $ICOWRAP

export SVGVIEW_1='0"/></svg>' #Viewer on
export SVGVIEW_2='4"/></svg>' #Viewer off
echo '<svg width="20" height="20" viewBox="0 0 100 100">
<path d="M0,50 C50,-20 90,50 100,50" stroke="#0" stroke-width="7" fill="none"/>
<path d="M0,50 C50,25 90,50 100,50M0,50 C50,120 90,50 100,50" stroke="#0" stroke-width="4" fill="#fff"/>
<circle cx="40" cy="58" r="22" fill="#1EB0FF"/>
<circle cx="40" cy="58" r="12" fill="#0"/>
<path d="M0L100 100M100 0L0 100" stroke="#0" stroke-width="'$SVGVIEW_1'' > $ICOVIEW

[[ -e $ICONHEX ]] || echo '<svg width="20" height="20" viewBox="0 0 100 100">
<rect height="100" width="100" fill="#fff"/>
<text font-size="60">
<tspan x="0" y="70">H</tspan>
<tspan x="33" fill="#f00">E</tspan>
<tspan x="58">X</tspan>
</text></svg>' > $ICONHEX

[[ -f "/usr/local/apps/ROX-Filer/ROX/MIME/application-x-xz.png" ]] && ICON_COMPRESS='image-name="/usr/local/apps/ROX-Filer/ROX/MIME/application-x-xz.png"'
}
{ #Help and tooltips
HLP1='Enter a shell command\n\nTo execute command press Enter or F4\nClose command box with Esc key or via menu\n\n\$@ can be used as placeholder for the basename of the currently selected file.\nTo use \$@ literally add a backslash: \\\$@'
export HLP2=$'\n\n\tInstant View mode disabled\n\n\tUse "Refresh" button or press F5\n\tto view a file'
TT01=$'Executables: Usage message (if available)\nDirectories: Total size, incl. subdirectories\nImages: Metadata (if available)\nArchives: List of archive contents\nSVG,XPM files: Source code\nHTML files: Plain text\nOther types: ignored'
TT02=$'Keep terminal open when selecting different file\ninstead of closing terminal and showing file contents\n\nThis setting has no effect while command box is closed,\nin which case the terminal keeps also closed'
TT03=$'Execute command shown in command box\n(menu item has no effect when command box is closed)'
TT04=$'Start/stop playing video/audio files\nPlay will start/stop immediately\nAs long as this menu item is checked, any selected video/audio files will play automatically'
TT05=$'Add line numbers to the content of the viewer pane\nThe selected file will not be modified'
TT06=$'Refresh viewer pane\n(Reset to default view)'
TT07=$'Open a command box beneath file list to enter shell commands'
TT08=$'Open command box with previously entered command'
TT09=$'Close command box'
TT10=$'View history of Commandbox\nWhen the Commandbox has focus the history can also be retrieved/closed by pressing Up/Down key'
TT11=$'Edit history of Commandbox ('$HISTORY')'
TT12=$'Clears history of Commandbox'
TT13=$'Open text file in default editor'
TT14=$'Open console\nand run selected file\n(if executable)'
TT15=$'Show in ROX-Filer window'
TT16=$'View file properties'
TT18=$'Rename selected file\nAdding path will move the file\n\nNote: Unlike ROX-Filer MMview supports rel.paths,\ne.g. '\''../foo'\'' will move '\''foo'\'' to parent folder'
TT19=$'Make a duplicate (copy) of the selected file in the same folder. Name MUST be different.\nAdding path will copy the file\n\nNote: Unlike ROX-Filer MMview supports rel.paths,\ne.g. '\''../foo'\'' will copy '\''foo'\'' to parent folder'
TT20=$'Delete file/directory\n\nNote: Wildcard characters supported, e.g. '\''*.mp3'\'' would deleted all mp3 files in the current folder'
TT21=$'Lclick: Fullscreen - normal size\nRclick: Fullscreen - fit to screen'
TT22=$'<b>Fullscreen - normal size</b>\nLclick: close fullscreen\nRclick: fit to screen'
TT23=$'<b>Fullscreen - fit to screen</b>\nLclick: normal size\nRclick: close fullscreen'
export TT24="<span font='14' color='#A52A2A'><b>Fullscreen</b>${BR}</span>Rclick: close fullscreen"
TT25=$'Rclick: Fullscreen'
TT27=$'Create new file or directory\nTo create directory: Append / (slash) to name'
TT31=$'Toggle Line Wrapping'
TT33=$'Create MD5 checksum\n\nChecked files and their checksum are kept in history.\nIdentical checksums in history (=identical files) are marked'
TT34=$'Compress/decompress\nselected file using gz compression\n\nWorks only on regular files,\ndirectories will be ignored'
TT39=$'Toggle Instant View mode'
TT40=$'Additional info for certain file types\n───────────────────────────\n'$TT01
TT42=$'Sends selected file to an application stored in ROX-Filer\x27s \x27\x27SendTo\x27\x27 directory\n\nA different directory can be defined by changing MMview\x27s SENDTOPATH variable'
TT43=$'Change application layout\n(arrange file chooser and viewer pane vertically)'
TT44="Lclick: Hexdump (max $(($HEXDUMP_MAXBYTES/1000))KB)${LF}Lpress: Hexdump in $HEXDUMP_VIEWER${LINE20}Rclick: Convert text string${LINE20}Mclick: ❰hex❱view (max $(($HEXDUMP_MAXBYTES/1000))KB)${LF}Mpress:❰hex❱view in $HEXDUMP_VIEWER${LINE20}For help press button > 1 sec"
export TT46="Displays up to $(($HEXDUMP_MAXBYTES/1000))KB of file content as hex values${LF}Left col displays decimal offsets, right col ASCII representations"
export TT47="Special hexdump format, displaying hex values only for (non printable) control characters, marked as ❰hex❱, and extended ASCII characters, marked as ◀hex▶. All other characters, incl. tab and linefeed, are displayed as normal text."
export TT48="Output in external editor, no size restriction"
export TT49="Breaks a text string into its individual characters and displays each character's hex value"

}
function fill_statusbar {
[[ -s $STBFILE ]] && { echo "$(< $STBFILE)" ; echo -n > $STBFILE; return ;}
[[ ! -L $vCHOOSER && ! -e $vCHOOSER ]] && return
[[ -L $vCHOOSER ]] && { LNK=' ➡ ' RP=$(realpath "$vCHOOSER") RP=${RP:-<dead link target>} ; true ;} || OP=$vCHOOSER # link
if [[ -L $vCHOOSER ]]; then
LNK=' ➡ '
RP=$(realpath "$vCHOOSER" 2>/dev/null)
(($?)) && echo "${vCHOOSER}${LNK}INVALID LINK TARGET ($(readlink "$vCHOOSER"))" && return
else OP=$vCHOOSER # link
fi
[[ -d ${OP}${RP} ]] && echo -n "${vCHOOSER}${LNK}${RP} │ x-directory" && return
echo -n "${vCHOOSER}${LNK}${RP} │ $(file -bi "${OP}${RP}")"
};export -f fill_statusbar
function view_instantly {
[[ $vMENU_PLAY = true ]] && busybox pkill MMplayme
[[ -s $MSGFILE ]] && echo -n > $MSGFILE
[[ $vMENU_WRAP = false ]] && echo 0 > $NB_PAGE || echo 1 > $NB_PAGE
echo -n "$vCHOOSER" | $CLIP -i # mimic ROX-Filer and send selected item to PRIMARY buffer

shopt -s nocasematch extglob
case $vSTATUSBAR in
*'x-directory') {
if [[ -z $(ls -A "$vCHOOSER") ]];then
MESSAGE=EMPTY
elif [[ -L $vCHOOSER ]];then
MESSAGE="SYMLINK to $(realpath "$vCHOOSER")"
elif [[ $vCHOOSER = /proc ]];then
MESSAGE="VIRTUAL FILE SYSTEM"
else
MESSAGE=$(busybox timeout -t1 du -hs "$vCHOOSER")
if (($?));then
MESSAGE="This takes too long. Instead press F1 for directory info"
else
MESSAGE="${MESSAGE%%[[:blank:]]*} (disk usage)"
fi
fi
};;
*│*'empty'*) {
if [[ "$vCHOOSER" = /proc/* ]] ;then # /proc contains seemingly empty virtual files that can't be read by linking them
MESSAGE=$(< "$vCHOOSER")
else
ln -fsn /dev/null $SYMLINK
return
fi
};;
*'.xpm '*|*'.pcx '*|*'.ani '*) { # Non scalable images
echo -n "Original Size" > $TMPFILE
echo 2 > $NB_PAGE
};;
*'.webp '*|*'.p'[bgp]'m '*) { # Images to be converted to JPG with ffmpeg
CONVERTER=$(type -p ffmpeg avconv | head -1)
if [[ $CONVERTER ]];then
rm -r ${DUMPDIR}* &>/dev/null
$CONVERTER -i "$vCHOOSER" ${DUMPDIR}converted.jpg &>/dev/null
if (($?));then
MESSAGE="${CONVERTER##*/} could not convert this image"
else
echo -n "Converted to JPG, scaled to fit viewer" > $TMPFILE
echo 3 > $NB_PAGE
ln -fsn ${DUMPDIR}converted.jpg $SYMLINK
return
fi
else
MESSAGE=$'\n\n\tDisplay requires ffmpeg or avconv'
fi
};;
*'.svg '*) {
echo -n "SVG image, scaled to fit viewer" > $TMPFILE
echo 3 > $NB_PAGE
};;
*'.psd '*|*'.dng '*|*'.cr2 '*|*[.mnp]'ef '*|*[.eo]'rf '*|*.[ams]'rw '*|*'.rw2 '*|*'.raf '*|*'.3fr '*) { #previews to be extracted with exiv2
rm -r ${DUMPDIR}* &>/dev/null
exiv2 -ep1 -l $DUMPDIR "$vCHOOSER"
if [[ $(ls -A "$DUMPDIR") ]];then
echo 3 > $NB_PAGE
ln -fsn "$DUMPDIR"* $SYMLINK
view_exif getEXIFMSG
echo -n "Extracted preview $EXIFMSG" > $TMPFILE
fi
return
};;
*│*'image'*) {
view_exif getSIZEEXIFMSG
[[ $IMAGE_W ]] && IMGSIZE=${IMAGE_W}x${IMAGE_H} #if no $IMAGE_W then exiv2 didn't understand format, e.g. ICO
if (( IMAGE_W > VIEWER_W || IMAGE_H > VIEWER_H ));then #if image bigger than pane calculate scaling for info only. Actual scaling is handled by pixmap widget with its WIDTH/HEIGHT arguments
SX=$(( 100 * VIEWER_W / IMAGE_W)) # scale in % ;Unrounded integer only, but good enough
SY=$(( 100 * VIEWER_H / IMAGE_H))
SCALE=$((SY < SX ? SY : SX)) # SCALE = SX or SY, whichever is smaller
echo -n "${SCALE}% of $IMGSIZE $EXIFMSG" > $TMPFILE
echo 3 > $NB_PAGE
else echo -n "Original size $IMGSIZE $EXIFMSG" > $TMPFILE
echo 2 > $NB_PAGE
fi
};;
*'charset=iso'*|*'charset='*'unknown'*) {
CHARSET=${vSTATUSBAR#*charset=}
[[ $CHARSET = *unknown* ]] && CHARSET=iso-8859-1 # Seems to work best
OOPS=$(iconv -f $CHARSET -t UTF-8 -o $MSGFILE -c "$vCHOOSER" 2>&1>/dev/null )
if [[ $OOPS ]] ;then
MESSAGE=$'Something went wrong.\n\nMaybe "iconv" is not installed or could not convert charset '"$CHARSET"$'\nHere is the error message:\n\n'"$OOPS"
else ln -fsn $MSGFILE $SYMLINK; return
fi
};;
*│*'text/'*|*│*'script'*|*│*'xml'*) {
[[ $vCHOOSER = /sys/* ]] && MESSAGE=$(< "$vCHOOSER" )
};;
*│*'video'*|*'.mkv '*|*'.mpg '*) {
MESSAGE=$($PROBE "$vCHOOSER" 2>&1)
[[ $vMENU_PLAY == true && $PLAY != false ]] && exec -a MMplayme $PLAY -x 320 -y 180 -i "$vCHOOSER" &
};;
*│*'audio'*|*'.mp3 '*|*'.ogg '*|*'.wma '*) {
[[ $vMENU_PLAY == true && $PLAY != false ]] && exec -a MMplayme $PLAY -nodisp -i "$vCHOOSER" &
if [[ $PROBE != false ]];then
FFP=$($PROBE "$vCHOOSER" 2>&1)
DUR=Duration:${FFP#*Duration:}
ID3=${FFP##*Metadata:$'\n'}
if [[ "$ID3" = "$FFP" ]] ;then # No Metadata found
ID3=""
else
EN_SPACE=$'\xe2\x80\x82' # Unicode U+2002 EN SPACE (" ")
ID3=${ID3/$DUR} # Strip trailing $DUR
ID3=${ID3// /$EN_SPACE} # replace SPACE with EN SPACE
ID3=${ID3//$EN_SPACE:/$'\t:'} # replace single EN SPACE followed by colon with a tab
fi
MESSAGE=$(echo -n "$DUR"$'\n\n'"$ID3" | sed "s/^[[:blank:]]*//")
else
MESSAGE='Display of audio specs requires "ffprobe" or "avprobe"'
fi
};;
*│*'executable'*) {
if [[ $(grep -i "usage:" "$vCHOOSER") ]] ;then
MESSAGE=$'⚫ Usage info for this file may exist. Try F1\n'
else vCHOOSER=/dev/null
fi
};;
*'.epub '*) {
echo 1 > $NB_PAGE
MESSAGE=$(
unzip -p "$vCHOOSER" *.opf |
{
echo -e "-------------------------------------\nPress F1 to read this eBook\n-------------------------------------\n"
sed -rn '
s/.*<dc:creator[^>]*>([^<]*).*/Author: \1\n/p
s/.*<dc:title[^>]*>([^<]*).*/Title: \1\n/p
s/.*<dc:description[^>]*>([^<]*).*/Description: \1\n/p'
}
)
};;
*│*'zip'*|*│*'xz'*|*'.7z '*|*'.deb '*|*'.iso '*) { #ARCHIVE .tar, .pet , .txz, .gz , .gzip, .bzip2, .zip, .7z, .deb, .iso, initrd*
MESSAGE=$'\n\tTry F1 to view archive contents'
};;
*) ln -fsn /dev/null $SYMLINK ; return ;;
esac
if [[ "$MESSAGE" ]];then
echo "$MESSAGE" > $MSGFILE
ln -fsn $MSGFILE $SYMLINK
else ln -fsn "$vCHOOSER" $SYMLINK
fi
};export -f view_instantly
function view_on_demand {
[[ $vMENU_WRAP = false ]] && echo 0 > $NB_PAGE || echo 1 > $NB_PAGE
FIGURESPACE=$'\xe2\x80\x87' # Unicode U+2007
shopt -s nocasematch
case $vSTATUSBAR in
*│*'executable'*) {
grep -iq "usage:" "$vCHOOSER" || return # exit function if 'usage:' not found
for ARG in --help -help;do
urxvt -g 1x1+0+0 -e bash -c " # open console in minimum size in upper left corner to reduce flicker
{ sleep 0.5; kill \$$ ;} & # let console commit suicide after 0.5sec.
\"$vCHOOSER\" $ARG &> $MSGFILE # redirect all output to MSGFILE
"
grep -iqm1 "usage:" $MSGFILE && break # leave loop if output contains 'usage:'
done
};;
*│*'directory'*) {
[[ -L $vCHOOSER || $vCHOOSER == /proc || $(< $MSGFILE) == EMPTY ]] && return
MSG="DIRECTORY \"${vCHOOSER##*/}\"${LF}${LF}▊COUNT${LF}"
MSG="${MSG}$(find "$vCHOOSER" -printf '%y %s\n' | awk 'BEGIN {fcnt=0} { if ($1!="d") { fsum+=$2 ; fcnt++ } else dcnt++ } END { printf "%s %'"'"'d %s\n" ,"Total: ",fsum," bytes ( Files:"fcnt", Directories:"dcnt" )\n"}')"
DU_ALL=$(du -h --max-depth=1 "$vCHOOSER"|sort -k2) # vCHOOSER on top, followed by subs; not yet sorted by size; du --max-depth more compatible than -d
DU_TOP="${LF}${LF}▊DISK USAGE${LF}${DU_ALL%%[[:blank:]]*}${LF}" # first line (=vCHOOSER)
if [[ ${MSG##*Directories:1 } = ')' ]] ;then
MSG="${MSG}${DU_TOP} └ (no subdirectories)"
else
DU_SUB=${DU_ALL#*$'\n'}
MSG=${MSG}${DU_TOP}$(echo -n "$DU_SUB" | sort -hr |awk '
{
$1=substr("───── "$1,length($1))
gsub(/\/.*\//,"")
print " └"$1" "$2" "substr($0,index($0,$3))
}')
fi
echo "$MSG" > $MSGFILE
};;
*'.svg '*|*'.xpm '*) {
ln -fsn "$vCHOOSER" $SYMLINK; return
};;
*'.epub '*) {
XDIALOG_ITEMS=$(unzip -l "$vCHOOSER" '*.htm*' | sort -k3 |sed -nr 's/[-0-9: ]*(.*\/)(.*\.html?$)/\1\2\n\2/p')
IFS=$'\n'
CHOICE=$(Xdialog --title "Select file to view" --stdout -ok-label View --no-tags --menubox "HTML files contained in eBook" 400x200 6 $XDIALOG_ITEMS)
(($?)) && return
view_htm2txt "$(unzip -p "$vCHOOSER" "$CHOICE")" > $MSGFILE
echo 1 > $NB_PAGE
};;
*'/initrd.gz'*) {
COMPRESSION=${vSTATUSBAR##*x-} # '/initrd.gz │ application/x-gzip; charset=binary' => 'gzip; charset=binary'
COMPRESSION=${COMPRESSION##*application/} # '/initrd.gz | application/gzip; charset=binary' => 'gzip; charset=binary'
COMPRESSION=${COMPRESSION%;*} # 'gzip; charset=binary' => 'gzip'
case $COMPRESSION in
gzip) CMND='gunzip -c -d' ;;
bzip2) CMND='bunzip2 -c -d' ;;
xz|lzma) CMND='unxz -c -d' ;;
lz4) CMND='unlz4 -c -d' ;;
*) CMND='cat' ;; # not compressed
esac
$CMND "$vCHOOSER" | busybox cpio -ivt | awk '
{
$1=toupper(substr($1,1,1)) # 1st char = filetype; uppercase helps to align proportional fonts
if ($1=="-") $1="F" # - = regular file
$3=substr("       "$3,length($3)) # padd with " " (Unicode U+2007 e2 80 87 FIGURE SPACE); max diplayed value: 99M
print $1,$3"\t"$4"\t"substr($0,index($0,$6)) # filetype \t size \t date \t filename
}' > $MSGFILE
};;
*│*'gzip'*|*│*'xz'*|*│*'bzip2'*) { # extensions .tar, .pet , .txz, .gz , .gzip, .bzip2
ARCH_OUTPUT=$(tar -vtf "$vCHOOSER" 2>/dev/null)
if [[ $ARCH_OUTPUT ]] ;then # output: tar extracted something, no output: most likely gzip contains to tarball, but in some cases of gzipped text files tar returned no output and exit code 0, so checking for exit codes does not help here
echo "$ARCH_OUTPUT" | awk '
{
if (substr($6,length($6),1) == "/" ) next # ignore folders
$3=substr("       "$3,length($3)) # padd with " " (Unicode U+2007 e2 80 87 FIGURE SPACE); max diplayed value: 99M
print $3,$4,$5"\t"$6 # size date time \t filename
}' > $MSGFILE
else # alternative if tar failed
case $vSTATUSBAR in
*│*gzip*) view_archive 'gzip -cd' ;; # display content of gzip compressed text files (e.g. .gnumeric)
*│*xz*) view_archive 'xz -cd' ;; # display content of xz compressed text files
*│*bzip2*) view_archive 'bzip2 -cd' ;; # display content of bzip2 compressed text files
esac
fi
};;
*'.deb '*) {
dpkg-deb -c "$vCHOOSER" | awk '
{
if (substr($6,length($6),1) == "/" ) next # ignore folders
$3=substr("       "$3,length($3)) # padd with " " (Unicode U+2007 e2 80 87 FIGURE SPACE); max diplayed value: 99M
print $3,$4,$5"\t"$6 # size date time \t filename
}' > $MSGFILE
};;
*'.iso '*) view_archive 'iso-info --no-header -l' ;;
*│*'/zip'*) view_archive 'unzip -l' ;;
*'.7z '*) view_archive '7z l' ;;
*│*'html'*|*'.html │'*|*'.htm │'*|*'.abw │'*|*'.ncd │'*) {
view_htm2txt $LWRAP_01 "$(< $vCHOOSER)" > $MSGFILE
};;
*) view_exif || { echo false && return ;}
esac
ln -fsn $MSGFILE $SYMLINK
};export -f view_on_demand
function file_properties {
FCONTENTS=$(file -bL "$vCHOOSER")
TMP=$IFS IFS='|'
STATARRAY=($(stat -c "%U|%G|%s|%b|%z|%y|%x|%A|%F" "$vCHOOSER"))
IFS=$TMP
## stat values
V0=${STATARRAY[0]} # owner
V1=${STATARRAY[1]} # group
V2=${STATARRAY[2]} # size
V3=${STATARRAY[3]} # blocks
V4=${STATARRAY[4]} # ctime
V5=${STATARRAY[5]} # mtime
V6=${STATARRAY[6]} # atime
V7=${STATARRAY[7]} # permissions
V8=${STATARRAY[8]} # type
## formatted stat values
case $V8 in
directory) F2=- F3=$(du -sh "$vCHOOSER") F3=${F3%%$'\t'*} ;;
*link) LINKED="LINKED " ;&
*) F2=$(printf "%'d\tbytes" $V2) F3=$(printf "%'d\tbytes %s" $((V3*512)) "($V3 blocks x 512 bytes)" ) ;;
esac
F4=${V4%%.*}
F5=${V5%%.*}
F6=${V6%%.*}
## Permissions
case ${V7:3:1} in # Owner
-) OX="--" ;;
x) OX="x-" ;;
s) OX="xx" ;;
S) OX="-x" ;;
esac
case ${V7:6:1} in # Group
-) GX="--" ;;
x) GX="x-" ;;
s) GX="xx" ;;
S) GX="-x" ;;
esac
case ${V7:9:1} in # World
-) WX="--" ;;
x) WX="x-" ;;
t) WX="xx" ;;
T) WX="-x" ;;
esac
F7="${V7:1:2}$OX"$'\n'"${V7:4:2}$GX"$'\n'"${V7:7:2}$WX"
F7=$(echo "$F7" | sed '
s/[rw]/x/g
s/./& /g' | sed '
1s/.*[x-]/Owner & SUID/
2s/.*[x-]/Group & SGID/
3s/.*[x-]/World & Sticky/
')
echo "\
${V8^^} \"${vCHOOSER##*/}\"

▊PROPERTIES
Owner,Group: ${V0},${V1}
File size: $F2
Used on disk: $F3

Change time: $F4
Modify time: $F5
Access time: $F6

▊PERMISSIONS
${TB} Read Write Exec
$F7

▊${LINKED}CONTENTS INDICATE...
${FCONTENTS}${LF}" > $MSGFILE

############# ROX RELATED STUFF ################
[[ $(type -p rox) ]]|| { ln -fsn $MSGFILE $SYMLINK ; return ;} # stop here if ROX not installed
ROXTYPE=$(rox_get_mime) # e.g. image/png
echo "\
▊ROX MIME TYPE
${ROXTYPE}${LF}" >> $MSGFILE
[[ -f $vCHOOSER ]] || { ln -fsn $MSGFILE $SYMLINK ; return ;} # stop here if file not a regular file

if [[ $ROXTYPE =~ executable|script|x-desktop ]] ;then echo "\
▊ROX RUN ACTION
Execute file" >> $MSGFILE
ln -fsn $MSGFILE $SYMLINK ; return
fi

ROXMIME=${ROXTYPE/\//_} # e.g. image/png => image_png

## Directories where ROX stores its "run action" scripts
TYPE_PATH[3]=/root/.config/rox.sourceforge.net/MIME-types/
TYPE_PATH[2]=/etc/xdg/rox.sourceforge.net/MIME-types/
TYPE_PATH[1]=/root/Choices/MIME-types/

TYPE_FILE[6]=${TYPE_PATH[3]}$ROXMIME
TYPE_FILE[5]=${TYPE_PATH[2]}$ROXMIME
TYPE_FILE[4]=${TYPE_PATH[1]}$ROXMIME
TYPE_FILE[3]=${TYPE_PATH[3]}${ROXMIME%%_*}
TYPE_FILE[2]=${TYPE_PATH[2]}${ROXMIME%%_*}
TYPE_FILE[1]=${TYPE_PATH[1]}${ROXMIME%%_*}
for i in {6..0}; do # From highest to lowest ROX priority; 0 will return TYPE_FILE[0] (=empty var) if none of the defined files exist
[[ -f ${TYPE_FILE[$i]} ]] && break
done
if ((i)) ;then
RUN_ACTION_FILE=${TYPE_FILE[$i]} # e.g. /root/.config/rox.sourceforge.net/MIME-types/text_plain
RUN_ACTION=$(grep "^[ ]*exec " "$RUN_ACTION_FILE") # more generous than ROX: 'exec' command not necessarily on 2nd line, may be preceded by whitespace
if [[ $RUN_ACTION ]];then # e.g. 'exec defaulttexteditor $1'
RUN_ACTION_APPLICATIONPATH=$(type -p $RUN_ACTION) # e.g. '/usr/local/bin/defaulttexteditor'
if [[ $RUN_ACTION_APPLICATIONPATH = */default* ]] ;then
DEF_APP=$(awk '/exec/ {print $2}' "$RUN_ACTION_APPLICATIONPATH" ) # e.g. geany
[[ $(type -p "$DEF_APP") ]] && DEF_ARROW=$"↳ ${DEF_APP}${LF}" # if exists preceded with arrow
fi
else
RUN_ACTION=$(< $RUN_ACTION_FILE) # = complete contents of run action file
fi
else
RUN_ACTION_FILE="( no run action file created )"
fi
echo "\
▊ROX RUN ACTION
File: $RUN_ACTION_FILE
Code: $RUN_ACTION
$DEF_ARROW" >> $MSGFILE
ln -fsn $MSGFILE $SYMLINK
} ;export -f file_properties
function file_openwith {
local FILETYPE MIME CMD TMP SNDTOCATGR SNDTOCUSTM SNDTOEVERY SNDTO_MIME SNDTOSPACE SPACER1 SPACER2 SPACER3 XDIALOGITEMS
[[ -d "$vCHOOSER" ]] && FILETYPE=directory || FILETYPE=file
MIME=$(rox_get_mime "$vCHOOSER")
MIME=${MIME/\//_} #e.g. image_jpeg
SNDTOSPACE=$'\n:\n─────────────────────\n' #Xdialog tag ':' is valid bash command
SNDTOCUSTM=$'Customize\nCustomize'
SNDTO_MIME=$(ls -d1 "${SENDTOPATH}".$MIME/* 2>/dev/null)
SNDTOCATGR=$(ls -d1 "${SENDTOPATH}".${MIME%_*}/* 2>/dev/null)
SNDTOEVERY=$(ls -d1 "${SENDTOPATH}"* 2>/dev/null)
[[ $SNDTO_MIME && $SNDTOCATGR ]] && SPACER1=$SNDTOSPACE
[[ $SNDTOCATGR && $SNDTOEVERY ]] && SPACER2=$SNDTOSPACE
[[ $SNDTO_MIME && $SNDTOEVERY && -z $SNDTOCATGR ]] && SPACER3=$SNDTOSPACE
XDIALOGITEMS=$(echo -n "${SNDTO_MIME}${SPACER1}${SNDTOCATGR}${SPACER2}${SPACER3}${SNDTOEVERY}${SNDTOSPACE}${SNDTOCUSTM}" | sed -r "s|.*/(.*)|&\n\1|" )
SENDTO_CHARS=$(echo "$XDIALOGITEMS" | wc -L) #width of longest line
SENDTO_LINES=$(echo "$XDIALOGITEMS" | wc -l) #no of lines
SENDTO_GEO_W=$((SENDTO_CHARS*3+40)) #estimated width
SENDTO_GEO_H=$((SENDTO_LINES*8+130)) #estimated height
TMP=$IFS; IFS=$LF
CMD=$(Xdialog --title "MMview" --no-tags --under-mouse --stdout --menubox "ROX \"Open With...\" actions for\n$FILETYPE \"${vCHOOSER##*/}\"" ${SENDTO_GEO_W}x${SENDTO_GEO_H} 6 $XDIALOGITEMS)
RET=$?
IFS=$TMP
(($RET)) && return
[[ $CMD == Customize ]] && { rox -d "$SENDTOPATH" & return ;}
[[ -d "$CMD" ]] && { "$CMD/AppRun" "$vCHOOSER" & return ;} # if CMD is directory assume ROX App
[[ $(rox -m "$CMD") = *desktop ]] && CMD=$(grep ^Exec= "$CMD") CMD=${CMD/Exec=} # if desktop file, retrieve command line after 'Exec='
[[ $(type -p "$CMD") ]] && "$CMD" "$vCHOOSER" &
} ;export -f file_openwith
function file_md5 {
[[ -d $vCHOOSER ]] && return
MD5CURRENT=$(md5sum "$vCHOOSER")
(($?)) && MD5CURRENT="???????????????????????????????? $vCHOOSER"
MD5HISTORY=$(
sed "s/◀/ / # remove all markers
\|$MD5CURRENT|d # same MD5 + filespec means file was tested already. Remove from list to prevent irritating ◀ marker
/${MD5CURRENT%% *}/ s/ /◀/ # append marker to any identical MD5 in list
" $MD5LIST 2>/dev/null
)
echo "${MD5CURRENT}${LF}${MD5HISTORY}" > $MD5LIST
echo $'▊ MD5SUM CURRENT FILE:\n'"$MD5CURRENT"$'\n\n▊ MD5SUM PREVIOUS FILES:\n'"$MD5HISTORY" > $MSGFILE
ln -fsn $MSGFILE $SYMLINK
}; export -f file_md5
function file_edit {
[[ -f $vCHOOSER ]] || return # editor should open only regular files ...
if [[ ! $vSTATUSBAR =~ (x-empty|│.*script|│.*text|│.*ascii|│.*utf-8) ]];then
Xdialog --title MMview --yesno "Does not appear to be a text file\nTry to open anyway?" x
(($?)) && return
fi
defaulttexteditor "$vCHOOSER" &
};export -f file_edit
function file_compress {
[[ $(file -b "$vCHOOSER") =~ ^gz ]] && gzip -d "$vCHOOSER" 2> $STBFILE || gzip -f "$vCHOOSER" 2> $STBFILE
[[ -s $STBFILE ]] || echo > $STBFILE # clear statusbar
ln -fsn /dev/null $SYMLINK
} ;export -f file_compress
function view_htm2txt {
echo "$1" | busybox tr '\r\n' '\x01' | sed -r ' # change Unix/Win/Mac line endings into hex01 markers, i.e put whole file content on a single line, then pipe to sed
s/^.*<\/head>//Ig # delete document declarations and the <head> section
s/<style[^<]*<\/style>//Ig # delete <style> sections
s/<script/\x0&/Ig # add NULL markers before <script>
s/\x0<script[^\x0]*<\/script>//Ig # delete <script> sections (unlike <style> sections <script> sections may contain < characters, making it difficult to match the content, hence the unlikely NULL character)
s/<pre>/\n&/Ig # put <pre> on separate line
s/<\/pre>/&\n/Ig' | sed -r ' # following /<pre>/! condition works only with fresh pipe (line structure changed!)
/<pre>/! s/\x01//Ig # delete all lineend markers except those between <pre> tags
s/&nbsp;|\t/ /g # replace &nbsp and tabs with normal space.
s/ +/ /g # reduce consecutive spaces (bad habit of NYT) to 1 space
s/>[ \x01]+</></g # delete all spaces or newlines between tags (if they are the only characters that separate the tags)
s/<metadata.*<\/metadata>// # delete <metadata> section (Abiword)
s/<d[ >][^<]*<\/d>//g # delete <d> sections (Abiword. <data> may contain multiple <d>, so greedy match will delete until last </d>. Good! Deleting whole <data> section instead might conflict with HTML5 <data>)
s/<div|<p[ >]/\x01\x01&/Ig # precede <div> and <p> with blank line (does not match <pre>,<progress>,<param>,<picture>)
s/<h[1-6]/\x01\x01● & /Ig # precede <h> with blank line and bullet
s/<dt/\x01\x01◆ &/Ig # precede <dt> (Notecase likes them) with lineend markers and bullet
s/<li/\x01• &/Ig # put <li> on new line and add bullet (unfortunately not possible to determine if list should be vertical or horizontal)
s/<\/h[1-9]|<dd|<tr|<br/\x01</Ig # precede </h <dd <tr <br with lineend marker, i.e. put them always on a new line
s/<[^>]*>|-->//g # delete all tags and --> (a leftover in Gtkdialog references)
s/&[lr]?d?quot?;/"/g # convert &ldquo; &rdquo; &quot;
s/&lt;/</g # convert &lt;
s/&gt;/>/g # convert &gt;
s/&amp;/\&/g # convert &amp;
s/&copy;/©/g # convert &copy;
s/^[ \x01]+// # delete first line if blank
s/\x01 +/\x01/g # delete all spaces at line start
s/[•◆●] *\x01//g # delete lines with orphaned bullets
s/\x01\x01\x01+/\x01\x01/g # reduce consecutive blank lines to 1 line
s/\x01/\n/g # change lineend markers back into newlines
'
}; export -f view_htm2txt
function convert_txt2hex {
TXTSTRING="$@"
ENCSTRING=$(printf %s "$TXTSTRING" | hexdump -ve '"\\"' -e '1/1 "x%02x"')
CHAR_CODE=$(printf %s "$TXTSTRING" | sed 's/./&\x0/g' | hexdump -ve '"\\"' -e '1/1 "x%02x"' | sed 's/\\x00/\n/g; s/\\x0a/&\n/g')
CHAR_CCNT=${#TXTSTRING}
CHAR_BCNT=${ENCSTRING//[^x]/}
CHAR_BCNT=${#CHAR_BCNT}
((CHAR_CCNT >1)) && CPLURAL=s
((CHAR_BCNT >1)) && BPLURAL=s
for line in $CHAR_CODE;do
NOTE=
case $line in
'\x09') CHAR='(TB)';;
'\x0a') CHAR='(LF)';;
'\x0d') CHAR='(CR)';;
'\x6c') CHAR="$line" NOTE='lowercase L';;
'\x49') CHAR="$line" NOTE='uppercase i';;
'\x7c') CHAR="$line" NOTE='vertical bar';;
'\x31') CHAR="$line" NOTE='number 1';;
'\x30') CHAR="$line" NOTE='number 0';;
'\x4f') CHAR="$line" NOTE='uppercase o';;
'\x20') CHAR="$line" NOTE='space';;
'\x7b') CHAR="$line" NOTE='left brace';;
'\x7d') CHAR="$line" NOTE='right brace';;
'\x28') CHAR="$line" NOTE='left parenthesis';;
'\x29') CHAR="$line" NOTE='right parenthesis';;
'\x27') CHAR="$line" NOTE='single quote';;
'\x60') CHAR="$line" NOTE='grave';;
*) CHAR="$line";;
esac
CNT=$((CNT+1))
MSG=${MSG}$(printf "%02d\t%b\t%s\t\t%s" $CNT $CHAR $line "$NOTE")$LF
done
echo -n "▊TEXT STRING ($CHAR_CCNT character${CPLURAL}; ${CHAR_BCNT} byte${BPLURAL}):
${TXTSTRING}${LF}
▊UTF-8 BYTESTRING:
${ENCSTRING}${LF}
▊CHARACTERS and their UTF-8 HEX CODES:
No. Char Hex Remarks${LINE40}${MSG}" > $MSGFILE

ln -fsn $MSGFILE $SYMLINK
echo true
} ;export -f convert_txt2hex
function view_archive {
TOOLNAME=${@%% *}
if type -p "$TOOLNAME" ;then
case $vSTATUSBAR in
*'.iso '*|*│*/zip*|*'.7z '*) $@ "$vCHOOSER" | sed "s/ /$S7/g" > $MSGFILE ;;
*) $@ "$vCHOOSER" > $MSGFILE ;;
esac
else echo "Requires command line tool $TOOLNAME" > $MSGFILE
fi
[[ $(file -b --mime-type $MSGFILE ) != 'text/plain' ]] && file -bL "$vCHOOSER" > $MSGFILE
ln -fsn $MSGFILE $SYMLINK
};export -f view_archive
function view_exif {
local SUMRY EXIV2 MDATA MSG IMGSIZE
EXIV2=$(exiv2 "${vCHOOSER}" 2>/dev/null)
RET=$?
((RET==1)) && return 1
case $1 in
getSIZEEXIFMSG) #called from view_instantly, case image
IMGSIZE=(${EXIV2#*Image size}) # ' : 1600 x 1200 ...'
IMAGE_W=${IMGSIZE[1]} # '1600'
IMAGE_H=${IMGSIZE[3]} # '1200'
;& #continue
getEXIFMSG) #called from view_instantly, case RAW extensions
EXIFMSG=
if ((RET==0));then #Exif data exist
EXIFMSG="Metadata:Exif"
[[ $(exiv2 -g "Exif.GPSInfo.GPSLatitude" -Pt "$vCHOOSER") ]] && EXIFMSG="$EXIFMSG,GPS"
[[ $EXIV2 =~ (Exif comment.*[^ :]) ]] && EXIFMSG="$EXIFMSG,Comment"
fi
return
;;
'') #no argument=called from view_on_demand
((RET>1)) && return 1
SUMRY=$(echo "$EXIV2" | sed "
1,4d #remove first 4 lines (basic data)
/:[[:blank:]]$/d #remove empty categories
s/ /${S7}${S8}/g #format 2nd column for proportional fonts
s/:/\t\t:/ #add tabs to align 2nd column
s/File size/& /" #"File size" needs extra space to align
)
MDATA=$(exiv2 -pa "${vCHOOSER}" |sed -r '
s/^([^ ]*) +[^ ]+ +[^ ]+(.*)$/\1=\2/ #skip 2nd and 3rd field
s/\x0//g #exiv2 output may contain NUL garbage; Gtk edit widget chokes on it
0,/^Exi/s//\n▊ EXIF METADATA\n&/ #Act on only 1st match of REGEX: 0,/REGEX/s//REPLACE_WITH/
0,/^Ipt/s//\n▊ IPTC METADATA\n&/
0,/^Xmp/s//\n▊ XMP METADATA\n&/
')
MSG="▊ EXIF SUMMARY${LF}${SUMRY}${LF}${MDATA}"
echo "$MSG" > $MSGFILE
;;
esac
}; export -f view_exif
function view_hexdump {
if [[ $1 == help ]];then
PRESS="Press means pressing button > ${THRESHOLD}/100 sec, i.e. slightly longer than normal click"
echo "▊BUTTON HELP${LF}
LeftClick Hexdump${LINE40}${TT46}${LF}
LeftPress Hexdump${LINE40}${TT48}${LF}${PRESS}${LF}
RightClick Convert text string${LINE40}${TT49}${LF}Multiline strings are supported.${LF}Useful to determine UTF-8 codes, line endings, whitespaces and hard to distinguish characters like lowercase 'L' and uppercase 'i'${LF}
MiddleClick ❰hex❱view${LINE40}${TT47}${LF}Useful for binary files with large text content but few non-ASCII characters, e.g. corrupted text files${LF}
MiddlePress ❰hex❱view${LINE40}${TT48}${LF}${PRESS}" > $MSGFILE
ln -fsn $MSGFILE $SYMLINK
return
fi
[[ -d $vCHOOSER ]] && return
FSIZE=$(stat -Lc %s "$vCHOOSER")
(( HEXDUMP_MAXBYTES < FSIZE )) && PARAM="-n$HEXDUMP_MAXBYTES" && MAXKB="(only first $((HEXDUMP_MAXBYTES/1000)) KB)"
case $1 in
dumphead) TITLE="▊HEXDUMP ${MAXKB}" ;;
dumpall) TITLE="▊HEXDUMP of $vCHOOSER" ;PARAM= ;;
markhead) TITLE="▊HEXVIEW nonprintable and extended ASCII ${MAXKB}" ;;
markall) TITLE="▊HEXVIEW nonprintable and extended ASCII of $vCHOOSER" ;PARAM= ;;
esac
TITLE=${TITLE}$LINE40
case $1 in
dump[ha]*) { echo -n "$TITLE" ; hexdump $PARAM -e '1 "%03_ad: "' -e '10/1 " %02X" "\t""|" ' -e '10/1 "%_p" "\n"' "$vCHOOSER" ;} > $MSGFILE
;;& #continue pattern match
dumpall) $HEXDUMP_VIEWER $MSGFILE & return ;;
mark[ha]*) { echo -e "$TITLE"$(hexdump $PARAM -ve '"\\"' -e '1/1 "x%02x"' "$vCHOOSER" | sed -r "
s/.x0[0-8b-f]|.x1[0-9a-f]|.x7f/❰& ❱/g #low ASCII exc. TAB and LF
s/.x[8-9a-f][0-9a-f]/◀& ▶/g #high ASCII
s/◀.x/◀/g
s/▶◀//g
s/ ▶/▶/g
s/❰.x/❰/g
s/❱❰//g
s/ ❱/❱/g") ;} > $MSGFILE

;;& #continue pattern match
markall) $HEXDUMP_VIEWER $MSGFILE & return ;;
esac
ln -fsn $MSGFILE $SYMLINK
} ;export -f view_hexdump
function find_again {
[[ -s $MSGFILE ]] && SOURCEFILE=$MSGFILE || SOURCEFILE=$vCHOOSER
FIND="$(< $FNDFILE)"
[[ $FIND ]] || return 1
[[ $vCHB_REGX = true ]] && OPT_REGX=-E TXT=Regex || OPT_REGX=-F TXT=Text
[[ $vCHB_CASE = true ]] && OPT_CASE= || OPT_CASE=-i
[[ $vCHB_WORD = true ]] && OPT_WORD=-w || OPT_WORD=
CNT=$(grep $OPT_REGX $OPT_CASE $OPT_WORD -o "$FIND" "$SOURCEFILE" |wc -l)
((CNT>1)) && PL=es || { ((CNT<1)) && CNT=no ;}
echo "$TXT Search for \"$FIND\" found $CNT match$PL" > $STBFILE
((CNT)) || return # avoid blank viewer pane
if [[ $vCHB_MARK = true ]];then
ESC=$(echo -e "\033")
grep --color=always -C999 $OPT_REGX $OPT_CASE $OPT_WORD -n "$FIND" "$SOURCEFILE" | sed "s/$ESC\[01;31m$ESC\[K/▊/g;s/$ESC\[[0-9;]*m$ESC\[K//g" > $TMPFILE
else
grep $OPT_REGX $OPT_CASE $OPT_WORD -n "$FIND" "$SOURCEFILE" > $TMPFILE
fi
ln -fsn $TMPFILE $SYMLINK
};export -f find_again
function add_linenumbers {
[[ -s $MSGFILE ]] && SOURCEFILE=$MSGFILE || SOURCEFILE=$vCHOOSER
grep -n ^ "$SOURCEFILE" > $TMPFILE
ln -fsn $TMPFILE $SYMLINK
};export -f add_linenumbers
function run_in_console {
[[ $vSTATUSBAR =~ (x-executable|x-shellscript) ]] &&
urxvt -title "$vCHOOSER" -e bash -c "\"$vCHOOSER\";echo;read -n1 -p \"Press any key to close\"" &
};export -f run_in_console
function run_dialog {
if [[ $1 ]];then # 1 argument = function called from Menu
printf "$1" > $D_TITLE
case $1 in
Rename|Duplicate)
printf "<b><big>${1^^}</big></b>" > $D_LABEL
printf "${vCHOOSER##*/}" > $D_DEFLT
;;
Create)
printf "<b><big>${1^^}</big> new file or directory</b> <small>(append / )</small>" > $D_LABEL
printf "$vCHOOSER" > $D_DEFLT
;;
Delete)
[[ -d $vCHOOSER ]] && D=" DIRECTORY"
printf "<span color='white' bgcolor='red'><b><big> ${1^^}$D </big></b></span>" > $D_LABEL
printf "${vCHOOSER##*/}" > $D_DEFLT
;;
Convert_Text*)
printf $'<b><big>Enter text string</big></b>\nto be converted to hex and single character codes' > $D_LABEL
printf "" > $D_DEFLT
;;
Find)
printf "<b><big>${1^^}</big></b>" > $D_LABEL
printf "$(<$FNDFILE)" > $D_DEFLT
;;
esac
else # no argumet = function called from dialog's OK button action
case $(<$D_TITLE) in
Rename|Duplicate|Delete|Create)cd "$(dir_name "$vCHOOSER")" ;;&
Create) [[ -e $vD_ENTRY ]] && echo "File/Directory \"$vD_ENTRY\" already exists" > $STBFILE && return
[[ ${vD_ENTRY: -1} = / ]] && mkdir -p "$vD_ENTRY" &> $STBFILE || touch "$vD_ENTRY" &> $STBFILE
;;
Rename) mv -uv "$vCHOOSER" "$vD_ENTRY" &> $STBFILE ;;
Duplicate) cp -ruv "$vCHOOSER" "$vD_ENTRY" &> $STBFILE ;;
Delete) if [[ $vD_ENTRY =~ [*?] ]];then
eval rm -v "$vD_ENTRY" &> $STBFILE
else
rm -rv "$vD_ENTRY" &> $STBFILE
fi ;;
Convert_Text) convert_txt2hex "$vD_ENTRY";;
Find) printf "$vD_ENTRY" > $FNDFILE
printf $vCHB_REGX > $FNDREGX
printf $vCHB_CASE > $FNDCASE
printf $vCHB_WORD > $FNDWORD
printf $vCHB_MARK > $FNDMARK
;;
esac
fi
}; export -f run_dialog
function run_shell_command {
cd "$(dir_name "$vCHOOSER")"
FCMD=${vCMDLINE//\$@/$(basename "$vCHOOSER")} # $@ = Basename of currently selected file/directory
OUT=$(bash -c "$FCMD" 2>&1)
RET=$?
[[ $RET = 0 ]] && [[ "$(tail -n1 $HISTORY)" != "$vCMDLINE" ]] && echo "$vCMDLINE" >> $HISTORY
[[ $RET$OUT = 0 ]] && return
echo -n "$OUT" > $MSGFILE
ln -fsn $MSGFILE $SYMLINK
};export -f run_shell_command
function rox_get_mime {
local ROX_M=$(rox -m "$vCHOOSER")
if [[ ! $(file -bL "$vCHOOSER") =~ executable|script && $ROX_M = *script* && $vCHOOSER = *.* ]];then
printf 'text/plain'
else printf $ROX_M
fi
} ;export -f rox_get_mime
function dir_name {
local d=${@%/*}
echo ${d:-/}
};export -f dir_name
function lastrites_save {
ACTWINID=$(xprop -root _NET_ACTIVE_WINDOW)
ACTWINID=${ACTWINID##* }
XWININFO=$(xwininfo -id $ACTWINID)
local ARRAY=(${XWININFO#* X: })
echo -n "${ARRAY[14]} ${ARRAY[16]}" > $LAST_WH
dir_name "$vCHOOSER" > $LASTDIR
};export -f lastrites_save
function lastrites_cleanup {
busybox pkill MMplayme
lastrites_save
[[ $(busybox pidof MMVprocess) =~ ^[0-9]+$ ]] || return # stop here if another instance running
[[ -d ${TEMPDIR} ]] && rm -rf ${TEMPDIR}*{.tmp,/}
}; export -f lastrites_cleanup
{ #TOOLTIP_DIALOG
export TOOLTIP_DIALOG='
<window type-hint="6" skip_taskbar_hint="true">
<eventbox>
<hbox spacing="9">
<pixmap icon_size="3"><input file stock="gtk-info"></input></pixmap>
<text use-markup="true"><input file>"'$TTPFILE'"</input></text>
</hbox>
</eventbox>
<variable>TOOLTIP_DIALOG</variable>
<action signal="enter-notify-event">closewindow:TOOLTIP_DIALOG</action>
<action signal="leave-notify-event">closewindow:TOOLTIP_DIALOG</action>
<action signal="focus-out-event"> closewindow:TOOLTIP_DIALOG</action>
<action signal="key-press-event"> closewindow:TOOLTIP_DIALOG</action>
<action signal="button-press-event">closewindow:TOOLTIP_DIALOG</action>
</window>
'
}
{ #FULLSCREEN_DIALOG_TXT
export FULLSCREEN_DIALOG_TXT='
<window type-hint="6">
<vbox scrollable="true" width="'$SCREEN_W'" height="'$SCREEN_H'" >
<notebook space-expand="true" space-fill="true" show-tabs="false">
<edit>
<input file>'$SYMLINK'</input>
<action signal="button-press-event" condition="command_is_true([[ $PTR_BTN == 3 ]] && echo true )">closewindow:FULLSCREEN_DIALOG_TXT</action>
</edit>
<edit wrap-mode="2">
<input file>'$SYMLINK'</input>
<action signal="button-press-event" condition="command_is_true([[ $PTR_BTN == 3 ]] && echo true )">closewindow:FULLSCREEN_DIALOG_TXT</action>
</edit>
<variable>vFDT_NOTE</variable>
<input>echo $vNOTE</input>
</notebook>
</vbox>
<variable>FULLSCREEN_DIALOG_TXT</variable>
<action signal="key-press-event" condition="command_is_true([[ $KEY_SYM == Escape ]] && echo true )">closewindow:FULLSCREEN_DIALOG_TXT</action>
<action signal="show">echo -n "$TT24" > $TTPFILE</action>
<action signal="show">refresh:vFDT_NOTE</action>
<action signal="map-event">launch:TOOLTIP_DIALOG</action>
</window>
'
}
{ #FULLSCREEN_DIALOG_PIX_NORMALSIZE
export FULLSCREEN_DIALOG_PIX_NORMALSIZE='
<window type-hint="6" border-width="0">
<vbox scrollable="true" shadow-type="0" width="'$SCREEN_W'" height="'$SCREEN_H'" >
<pixmap space-expand="true" space-fill="true" tooltip-markup="'$TT22'">
<input file>'$SYMLINK'</input>
</pixmap>
</vbox>
<variable>FULLSCREEN_DIALOG_PIX_NORMALSIZE</variable>
<action signal="button-press-event" condition="command_is_true( [[ $PTR_BTN == [12] ]] && echo true )">closewindow:FULLSCREEN_DIALOG_PIX_NORMALSIZE</action>
<action signal="button-press-event" condition="command_is_true( [[ $PTR_BTN == [12] ]] && echo true )">closewindow:FULLSCREEN_DIALOG_PIX_FIT2SCREEN</action>
<action signal="button-press-event" condition="command_is_true( [[ $PTR_BTN == 3 ]] && echo true )">launch: FULLSCREEN_DIALOG_PIX_FIT2SCREEN</action>
<action signal="key-press-event" condition="command_is_true( [[ $KEY_SYM == Escape ]] && echo true )">closewindow:FULLSCREEN_DIALOG_PIX_NORMALSIZE</action>
<action signal="key-press-event" condition="command_is_true( [[ $KEY_SYM == Escape ]] && echo true )">closewindow:FULLSCREEN_DIALOG_PIX_FIT2SCREEN</action>
</window>
'
}
{ #FULLSCREEN_DIALOG_PIX_FIT2SCREEN
export FULLSCREEN_DIALOG_PIX_FIT2SCREEN='
<window type-hint="6" border-width="0" width-request="'$SCREEN_W'" height-request="'$SCREEN_H'">
<eventbox>
<pixmap tooltip-markup="'$TT23'">
<width>'$SCREEN_W'</width>
<height>'$SCREEN_H'</height>
<input file>'$SYMLINK'</input>
</pixmap>
</eventbox>
<variable>FULLSCREEN_DIALOG_PIX_FIT2SCREEN</variable>
<action signal="button-press-event" condition="command_is_true( [[ $PTR_BTN == [23] ]] && echo true )">closewindow:FULLSCREEN_DIALOG_PIX_FIT2SCREEN</action>
<action signal="button-press-event" condition="command_is_true( [[ $PTR_BTN == [23] ]] && echo true )">closewindow:FULLSCREEN_DIALOG_PIX_NORMALSIZE</action>
<action signal="button-press-event" condition="command_is_true( [[ $PTR_BTN == 1 ]] && echo true )">launch: FULLSCREEN_DIALOG_PIX_NORMALSIZE</action>
<action signal="key-press-event" condition="command_is_true( [[ $KEY_SYM == Escape ]] && echo true )">closewindow:FULLSCREEN_DIALOG_PIX_FIT2SCREEN</action>
<action signal="key-press-event" condition="command_is_true( [[ $KEY_SYM == Escape ]] && echo true )">closewindow:FULLSCREEN_DIALOG_PIX_NORMALSIZE</action>
</window>
'
}
{ #MULTI_DIALOG
export MULTI_DIALOG='
<window modal="true" window-position="2" image-name="'$ICONMMV'" resizable="false">
<vbox>
<text xalign="0" use-markup="true"><input file>'$D_LABEL'</input></text>
<entry activates_default="true">
<input file>'$D_DEFLT'</input>
<variable>vD_ENTRY</variable>
</entry>
<vbox>
<checkbox label="Use regular expressions"><variable>vCHB_REGX</variable></checkbox>
<checkbox label="Match case"> <variable>vCHB_CASE</variable></checkbox>
<checkbox label="Match only whole word"> <variable>vCHB_WORD</variable></checkbox>
<hseparator></hseparator>
<checkbox label="Use inline markers (do not extract matching lines)"><variable>vCHB_MARK</variable></checkbox>
<variable>vD_CHECKBOXES</variable>
</vbox>
<hbox>
<button label="gtk-cancel" use-stock="true" width-request="180">
<variable>vD_BTN_CANCEL</variable>
<action>closewindow:MULTI_DIALOG</action>
<action>presentwindow:MAIN_DIALOG</action>
</button>
<button label="gtk-ok" use-stock="true" width-request="180" can-default="true" has-default="true">
<action condition="command_is_true(run_dialog)">activate:vMACRO_VIEWTEXT</action>
<action condition="command_is_true([[ -s $STBFILE ]] && echo true )">refresh:vSTATUSBAR</action>
<action condition="visible_is_true(vD_CHECKBOXES)">activate:vMENU_FINDAGAIN</action>
<action>closewindow:MULTI_DIALOG</action>
<action>presentwindow:MAIN_DIALOG</action>
</button>
</hbox>
</vbox>
<variable>MULTI_DIALOG</variable>
<input file>'$D_TITLE'</input>
<action signal="map-event">$WMCTRL -r :ACTIVE: -b add,above &</action>
<action signal="show" condition="command_is_true([[ $(<$D_TITLE) != Find ]] && echo true )">hide:vD_CHECKBOXES</action>
<action signal="show" condition="command_is_true([[ $(<$D_TITLE) != Find ]] && echo true )">break:</action>
<action signal="show" condition="command_is_true( echo $(<$FNDREGX) )">activate:vCHB_REGX</action>
<action signal="show" condition="command_is_true( echo $(<$FNDCASE) )">activate:vCHB_CASE</action>
<action signal="show" condition="command_is_true( echo $(<$FNDWORD) )">activate:vCHB_WORD</action>
<action signal="show" condition="command_is_true( echo $(<$FNDMARK) )">activate:vCHB_MARK</action>
<action signal="key-press-event" condition="command_is_true([ $KEY_SYM = Escape ] && echo true )">closewindow:MULTI_DIALOG</action>
<action signal="key-press-event" condition="command_is_true([ $KEY_SYM = Escape ] && echo true )">presentwindow:MAIN_DIALOG</action>
</window>'
}
{ #MACROS
MACROS='
<menu visible="false">
<menuitem>
<variable>vMACRO_REFRESH</variable>
<action>refresh:vSTATUSBAR</action>
<action condition="active_is_true(vMENU_DISABLEVIEW)">break:</action>
<action>activate:vMACRO_REFRESH_SUBROUTINE</action>
</menuitem>
<menuitem>
<variable>vMACRO_REFRESH_FORCE</variable>
<action>refresh:vSTATUSBAR</action>
<action>activate:vMACRO_REFRESH_SUBROUTINE</action>
</menuitem>
<menuitem>
<variable export="false">vMACRO_REFRESH_SUBROUTINE</variable>
<action>view_instantly</action>
<action condition="command_is_true([[ $(<$NB_PAGE) != $vNOTE ]] && echo true )">refresh:vNOTE</action>
<action condition="command_is_true([[ $vNOTE == 0 ]] && echo true )">refresh:vEDI0</action>
<action condition="command_is_true([[ $vNOTE == 1 ]] && echo true )">refresh:vEDI1</action>
<action condition="command_is_true([[ $vNOTE == 2 ]] && echo true )">refresh:vPIX2</action>
<action condition="command_is_true([[ $vNOTE == 2 ]] && echo true )">refresh:vTXT2</action>
<action condition="command_is_true([[ $vNOTE == 3 ]] && echo true )">refresh:vPIX3</action>
<action condition="command_is_true([[ $vNOTE == 3 ]] && echo true )">refresh:vTXT3</action>
</menuitem>
<menuitem>
<variable export="false">vMACRO_WRITECMD</variable>
<action>grabfocus:vCMDLINE</action>
<action>clear:vCMDLINE</action>
<action>refresh:vCMDLINE</action>
</menuitem>
<menuitem>
<variable export="false">vMACRO_OPEN_COMMANDBOX</variable>
<action>disable:vMENU_CMDBOX_OPEN</action>
<action>enable:vMENU_F4</action>
<action>show:vCOMMANDBOX</action>
</menuitem>
<menuitem>
<variable export="false">vMACRO_VIEWTEXT</variable>
<action condition="active_is_true (vMENU_WRAP)">printf 1 > $NB_PAGE</action>
<action condition="active_is_false(vMENU_WRAP)">printf 0 > $NB_PAGE</action>
<action condition="active_is_true (vMENU_WRAP)">refresh:vEDI1</action>
<action condition="active_is_false(vMENU_WRAP)">refresh:vEDI0</action>
<action>refresh:vNOTE</action>
</menuitem>
<menuitem>
<variable export="false">vMACRO_VIEWTEXT_WRAPPED</variable>
<action>printf 1 > $NB_PAGE</action>
<action>refresh:vEDI1</action>
<action>refresh:vNOTE</action>
</menuitem>
<menuitem>
<variable export="false">vMACRO_RESTART</variable>
<action>lastrites_save;exec "$APP_PATH" &</action>
<action>exit:</action>
</menuitem>
</menu>
'
}
{ #MENU
MENU='
<menubar height-request="'$MENUBAR_HIGHT'" space-fill="true" space-expand="true">
'$MACROS'
<menu label="File">
<menuitem label="New" accel-key="0x6e" accel-mods="4" stock-id="gtk-file" tooltip-text="'$TT27'">
<action>run_dialog Create</action>
<action>launch:MULTI_DIALOG</action>
</menuitem>
<menuitemseparator></menuitemseparator>
<menuitem label="Rename" accel-key="0x72" accel-mods="4"stock-id="gtk-strikethrough" tooltip-text="'$TT18'">
<action>run_dialog Rename</action>
<action>launch:MULTI_DIALOG</action>
</menuitem>
<menuitem label="Duplicate (copy)" accel-key="0x64" accel-mods="4"stock-id="gtk-copy" tooltip-text="'$TT19'">
<action>run_dialog Duplicate</action>
<action>launch:MULTI_DIALOG</action>
</menuitem>
<menuitem label="Compress/Decompress" accel-key="0x47" accel-mods="4" '$ICON_COMPRESS' tooltip-text="'$TT34'">
<variable export="false">vMENU_COMPRESS</variable>
<width>16</width>
<action>file_compress</action>
<action>refresh:vSTATUSBAR</action>
</menuitem>
<menuitem label="Edit" accel-key="0x45" accel-mods="4" stock-id="gtk-edit" tooltip-text="'$TT13'">
<variable export="false">vMENU_OPENEDITOR</variable>
<action>file_edit</action>
</menuitem>
<menuitem label="Delete" accel-key="0x78" accel-mods="4" stock-id="gtk-delete" tooltip-text="'$TT20'">
<action>run_dialog Delete</action>
<action>launch:MULTI_DIALOG</action>
</menuitem>
<menuitemseparator></menuitemseparator>
<menuitem label="Run in console" accel-key="0xffc2" accel-mods="4" stock-id="gtk-execute" tooltip-text="'$TT14'">
<variable export="false">vMENU_RUNCONSOLE</variable>
<action>run_in_console</action>
</menuitem>
<menuitem label="Show in ROX" accel-key="0x72" accel-mods="5" stock-id="gtk-jump-to" tooltip-text="'$TT15'">
<variable export="false">vMENU_SHOWINROX</variable>
<action>rox -s "$vCHOOSER"</action>
</menuitem>
<menuitem label="Open With ... (MiddleClick)" tooltip-text="'$TT42'">
<variable export="false">vMENU_OPENWITH</variable>
<action>file_openwith &</action>
</menuitem>
<menuitemseparator></menuitemseparator>
<menuitem label="Properties" accel-key="0x70" accel-mods="4" stock-id="gtk-properties" tooltip-text="'$TT16'">
<variable export="false">vMENU_PROPERTIES</variable>
<action>file_properties</action>
<action>activate:vMACRO_VIEWTEXT</action>
</menuitem>
<menuitem label="MD5 checksum" accel-key="0x35" accel-mods="4" stock-id="gtk-properties" tooltip-text="'$TT33'">
<variable export="false">vMENU_MD5</variable>
<action>file_md5</action>
<action>activate:vMACRO_VIEWTEXT</action>
</menuitem>
<menuitemseparator></menuitemseparator>
<menuitem label="Quit" accel-key="0x071" accel-mods="4" stock-id="gtk-quit">
<action>activate:vBTN_QUIT</action>
</menuitem>
</menu>
<menu label="Search">
<menuitem label="Find ..." accel-key="0x46" accel-mods="4" stock-id="gtk-find">
<action>run_dialog Find</action>
<action>launch:MULTI_DIALOG</action>
</menuitem>
<menuitem label="Find again" accel-key="0xffc0" accel-mods="0">
<variable export="false">vMENU_FINDAGAIN</variable>
<action>find_again</action>
<action>refresh:vSTATUSBAR</action>
<action>activate:vMACRO_VIEWTEXT</action>
</menuitem>
</menu>
<menu label="View">
<menuitem label="Additional info (see tooltip)" tooltip-text="'$TT01'" accel-key="0xffbe" accel-mods="0" stock-id="gtk-info">
<variable export="false">vMENU_F1</variable>
<action condition="command_is_true( [[ $vSTATUSBAR != *│* ]] && echo true )">refresh:vSTATUSBAR</action>
<action condition="command_is_false(view_on_demand)">break:</action>
<action condition="command_is_true([[ $(<$NB_PAGE) != $vNOTE ]] && echo true )">refresh:vNOTE</action>
<action condition="command_is_true([[ $vNOTE == 0 ]] && echo true )">refresh:vEDI0</action>
<action condition="command_is_true([[ $vNOTE == 1 ]] && echo true )">refresh:vEDI1</action>
<action condition="command_is_true([[ $vNOTE == 2 ]] && echo true )">refresh:vPIX2</action>
<action condition="command_is_true([[ $vNOTE == 2 ]] && echo true )">refresh:vTXT2</action>
<action condition="command_is_true([[ $vNOTE == 3 ]] && echo true )">refresh:vPIX3</action>
<action condition="command_is_true([[ $vNOTE == 3 ]] && echo true )">refresh:vTXT3</action>
</menuitem>
<menuitemseparator></menuitemseparator>
<menuitem label="Hexdump (max '$((HEXDUMP_MAXBYTES/1000))'KB)" image-name="'$ICONHEX'" accel-key="0x48" accel-mods="4" tooltip-text="'$TT46'">
<variable>vMENU_HEXDUMP_HEAD</variable>
<width>16</width>
<action>view_hexdump dumphead</action>
<action>activate:vMACRO_VIEWTEXT</action>
</menuitem>
<menuitem label="Convert text string ..." image-name="'$ICONHEX'" accel-key="0x64" accel-mods="5" tooltip-text="'$TT49'">
<variable>vMENU_CHAR2HEX</variable>
<width>16</width>
<action>run_dialog Convert_Text</action>
<action>launch:MULTI_DIALOG</action>
</menuitem>
<menu label="More View Options for Binaries...">
<menuitem label="Hexdump (in '"$HEXDUMP_VIEWER"')" image-name="'$ICONHEX'" tooltip-text="'$TT48'">
<variable>vMENU_HEXDUMP_ALL</variable>
<width>16</width>
<action>view_hexdump dumpall</action>
</menuitem>
<menuitem label="❰hex❱view (max '$((HEXDUMP_MAXBYTES/1000))'KB)" image-name="'$ICONHEX'" tooltip-text="'$TT47'">
<variable>vMENU_HEXMARK_HEAD</variable>
<width>16</width>
<action>view_hexdump markhead</action>
<action>activate:vMACRO_VIEWTEXT_WRAPPED</action>
</menuitem>
<menuitem label="❰hex❱view (in '"$HEXDUMP_VIEWER"')" image-name="'$ICONHEX'" tooltip-text="'$TT48'">
<variable>vMENU_HEXMARK_ALL</variable>
<width>16</width>
<action>view_hexdump markall</action>
</menuitem>
<menuitem visible="false">
<variable>vMENU_HEXDUMP_HELP</variable>
<action>view_hexdump help</action>
<action>activate:vMACRO_VIEWTEXT_WRAPPED</action>
</menuitem>
</menu>
<menuitemseparator></menuitemseparator>
<menuitem label="Refresh" accel-key="0xffc2" accel-mods="0" stock-id="gtk-refresh" tooltip-text="'$TT06'">
<variable export="false">vMENU_REFRESH</variable>
<action>echo 0 > $NB_PAGE</action>
<action>activate:vMACRO_REFRESH_FORCE</action>
</menuitem>
<menuitem label="Disable Instant View Mode" checkbox="" tooltip-text="">
<variable>vMENU_DISABLEVIEW</variable>
<action condition="command_is_true( [[ $vMENU_DISABLEVIEW != $vBTN_DISABLEVIEW ]] && echo true )">activate:vBTN_DISABLEVIEW</action>
<action>if true echo "$HLP2" > $MSGFILE && ln -fsn $MSGFILE $SYMLINK</action>
<action>if true activate:vMACRO_VIEWTEXT</action>
<action>if false activate:vMENU_REFRESH</action>
</menuitem>
<menuitem label="Vertical layout" tooltip-text="'$TT43'" checkbox="'$LAYOUT_V'" >
<variable>vMENU_LAYOUT</variable>
<action>if true > $BOXMODE</action>
<action>if false rm $BOXMODE</action>
<action>activate:vMACRO_RESTART</action>
</menuitem>
</menu>
<menu label="Play">
<menuitem label="Play video/audio files" checkbox="" accel-key="0x7a" accel-mods="4" tooltip-text="'$TT04'">
<variable>vMENU_PLAY</variable>
<action>if false busybox pkill MMplayme</action>
<action>if true view_instantly</action>
</menuitem>
</menu>
<menu label="Document">
<menuitem label="Line Wrapping" checkbox="" tooltip-text="'$TT31'">
<variable>vMENU_WRAP</variable>
<action condition="command_is_true( (( $vNOTE < 2 )) && echo true )">activate:vMACRO_VIEWTEXT</action>
<action condition="command_is_true( [[ $vMENU_WRAP != $vBTN_WRAP ]] && echo true )">activate:vBTN_WRAP</action>
</menuitem>
<menuitem label="Show Line Numbers" accel-key="0xffbf" accel-mods="0" tooltip-text="'$TT05'">
<action>add_linenumbers</action>
<action>activate:vMACRO_VIEWTEXT</action>
</menuitem>
</menu><menu label="Commandbox">
<menuitem label="Open" accel-key="0x21" accel-mods="1" tooltip-text="'$TT07'">
<variable>vMENU_CMDBOX_OPEN</variable>
<action>activate:vMACRO_OPEN_COMMANDBOX</action>
<action>echo " \"\$@\" " > $COMMAND</action>
<action>activate:vMACRO_WRITECMD</action>
</menuitem>
<menuitem label="Open with last command" accel-key="0x21" accel-mods="5" tooltip-text="'$TT08'">
<action>activate:vMACRO_OPEN_COMMANDBOX</action>
<action>tail -n1 $HISTORY > $COMMAND</action>
<action>activate:vMACRO_WRITECMD</action>
</menuitem>
<menuitem label="Close" accel-key="0xff1b" accel-mods="0" stock-id="gtk-close" tooltip-text="'$TT09'">
<action>hide:vCOMMANDBOX</action>
<action>enable:vMENU_CMDBOX_OPEN</action>
<action>disable:vMENU_F4</action>
<action>activate:vMENU_REFRESH</action>
</menuitem>
<menuitem label="Run command" accel-key="0xffc1" accel-mods="0" stock-id="gtk-execute" tooltip-text="'$TT03'">
<variable export="false">vMENU_F4</variable>
<action>run_shell_command</action>
<action>activate:vMACRO_VIEWTEXT</action>
</menuitem>
<menuitemseparator></menuitemseparator>
<menuitem label="View Command History" image-name="'$ICONMMV'" tooltip-text="'$TT10'">
<variable>vMENU_VIEWHISTORY</variable>
<width>16</width>
<action>ln -fsn $HISTORY $SYMLINK</action>
<action>activate:vMACRO_VIEWTEXT</action>
</menuitem>
<menuitem label="Edit Command History" stock-id="gtk-edit" tooltip-text="'$TT11'">
<action>defaulttexteditor $HISTORY</action>
</menuitem>
<menuitem label="Clear Command History" stock-id="gtk-delete" tooltip-text="'$TT12'">
<action>echo -n > $HISTORY</action>
</menuitem>
</menu>
</menubar>
'
}
{ #TOOLBAR
TOOLBAR='<button can-focus="false" tooltip-text="'$TT44'">
<input file>"'$ICONHEX'"</input>
<action signal="button-press-event"> refresh:vTSTART</action>
<action signal="button-release-event">refresh:vDURATION</action>
<action signal="button-release-event" condition="command_is_true( (( vDURATION>100 )) && echo true )">activate:vMENU_HEXDUMP_HELP</action>
<action signal="button-release-event" condition="command_is_true( (( vDURATION>100 )) && echo true )">break:</action>
<action signal="button-release-event" condition="command_is_true( [[ $PTR_BTN == 1 ]] && ((vDURATION<=THRESHOLD)) && echo true )">activate:vMENU_HEXDUMP_HEAD</action>
<action signal="button-release-event" condition="command_is_true( [[ $PTR_BTN == 1 ]] && ((vDURATION >THRESHOLD)) && echo true )">activate:vMENU_HEXDUMP_ALL</action>
<action signal="button-release-event" condition="command_is_true( [[ $PTR_BTN == 2 ]] && ((vDURATION<=THRESHOLD)) && echo true )">activate:vMENU_HEXMARK_HEAD</action>
<action signal="button-release-event" condition="command_is_true( [[ $PTR_BTN == 2 ]] && ((vDURATION >THRESHOLD)) && echo true )">activate:vMENU_HEXMARK_ALL</action>
<action signal="button-release-event" condition="command_is_true( [[ $PTR_BTN == 3 ]] && echo true )">activate:vMENU_CHAR2HEX</action>
</button>

<togglebutton can-focus="false" tooltip-text="'$TT31'">
<variable>vBTN_WRAP</variable>
<input file>"'$ICOWRAP'"</input>
<action>if true sed -i "s|$SVGWRAP_1|$SVGWRAP_2|" "'$ICOWRAP'"</action>
<action>if false sed -i "s|$SVGWRAP_2|$SVGWRAP_1|" "'$ICOWRAP'"</action>
<action condition="command_is_true( [[ $vMENU_WRAP != $vBTN_WRAP ]] && echo true )">activate:vMENU_WRAP</action>
<action>refresh:vBTN_WRAP</action>
</togglebutton>
<button can-focus="false" tooltip-text="'$TT16'"><action>activate:vMENU_PROPERTIES</action><input file stock="gtk-properties"></input></button>
<button can-focus="false" tooltip-text="'$TT13'"><action>activate:vMENU_OPENEDITOR</action><input file stock="gtk-edit"></input></button>
<button can-focus="false" tooltip-text="'$TT15'"><action>activate:vMENU_SHOWINROX</action><input file stock="gtk-jump-to"></input></button>
<togglebutton can-focus="false" tooltip-text="'"$TT39"'" can-focus="false">
<variable>vBTN_DISABLEVIEW</variable>
<input file>"'$ICOVIEW'"</input>
<action>if true sed -i "s|$SVGVIEW_1|$SVGVIEW_2|" "'$ICOVIEW'"</action>
<action>if false sed -i "s|$SVGVIEW_2|$SVGVIEW_1|" "'$ICOVIEW'"</action>
<action>refresh:vBTN_DISABLEVIEW</action>
<action condition="command_is_true( [[ $vMENU_DISABLEVIEW != $vBTN_DISABLEVIEW ]] && echo true )">activate:vMENU_DISABLEVIEW</action>
</togglebutton>
<button can-focus="false" tooltip-text="'$TT06'"><action>activate:vMENU_REFRESH</action><input file stock="gtk-refresh"></input></button>
<button can-focus="false" tooltip-text="'$TT40'"><action>activate:vMENU_F1</action><input file stock="gtk-info"></input></button>'
}
{ #MAIN_DIALOG
export MAIN_DIALOG='
<window title="MMview" default-width="'$DEFAULT_WIDTH'" default-height="'$DEFAULT_HIGHT'" allow-shrink="true" margin="'$WINDOW_MARGIN'" image-name="'$ICONMMV'">
<vbox space-expand="true" space-fill="true" spacing="'$WIDGETSPACING'">
<hbox space-expand="false" spacing="0">
'"$MENU"'
'"$TOOLBAR"'
</hbox>
<'$BOX'box space-expand="true" spacing="'$CENTERSPACING'">
<chooser width-request="'$CHOOSER_WIDTH'" height-request="'$CHOOSER_HIGHT'" space-expand="false" space-fill="true">
<variable>
"vCHOOSER"
</variable>
<default>"'$DEFAULT_DIRECTORY'"</default>
<action>rox "$vCHOOSER"</action>
<action signal="button-release-event">[[ $PTR_BTN = 2 ]] && file_openwith &</action>
<action when="update-preview">activate:vMACRO_REFRESH</action>
</chooser>
<'$SEP'separator space-expand="false"></'$SEP'separator>
<notebook space-fill="true" space-expand="true" show-tabs="false" show-border="false">
<vbox tooltip-text="'$TT25'">
<edit left-margin="'$L_EDIT_MARGIN'">
<variable export="false">
"vEDI0"
</variable>
<input file>'$SYMLINK'</input>
<action signal="button-press-event" condition="command_is_false( echo $((PTR_BTN-3)) )">launch:FULLSCREEN_DIALOG_TXT</action>
</edit>
</vbox>
<vbox tooltip-text="'$TT25'">
<edit left-margin="'$L_EDIT_MARGIN'" wrap-mode="2">
<variable export="false">
"vEDI1"
</variable>
<input file>'$SYMLINK'</input>
<action signal="button-press-event" condition="command_is_false( echo $((PTR_BTN-3)) )">launch:FULLSCREEN_DIALOG_TXT</action>
</edit>
</vbox>
<eventbox tooltip-text="'$TT21'">
<vbox>
<text>
<variable export="false">
"vTXT2"
</variable>
<input file>"'$TMPFILE'"</input>
</text>
<vbox scrollable="true" shadow-type="0" space-expand="true">
<pixmap>
<variable export="false">
"vPIX2"
</variable>
<input file>'$SYMLINK'</input>
</pixmap>
</vbox>
</vbox>
<action signal="button-press-event" condition="command_is_true( [[ $PTR_BTN == 1 ]] && echo true )">launch:FULLSCREEN_DIALOG_PIX_NORMALSIZE</action>
<action signal="button-press-event" condition="command_is_true( [[ $PTR_BTN == 3 ]] && echo true )">launch:FULLSCREEN_DIALOG_PIX_FIT2SCREEN</action>
</eventbox>
<eventbox tooltip-text="'$TT21'">
<vbox>
<text>
<variable export="false">
"vTXT3"
</variable>
<input file>"'$TMPFILE'"</input>
</text>
<pixmap space-expand="true">
<variable export="false">
"vPIX3"
</variable>
<width>'$VIEWER_W'</width>
<height>'$VIEWER_H'</height>
<input file>'$SYMLINK'</input>
</pixmap>
</vbox>
<action signal="button-press-event" condition="command_is_true( [[ $PTR_BTN == 1 ]] && echo true )">launch:FULLSCREEN_DIALOG_PIX_NORMALSIZE</action>
<action signal="button-press-event" condition="command_is_true( [[ $PTR_BTN == 3 ]] && echo true )">launch:FULLSCREEN_DIALOG_PIX_FIT2SCREEN</action>
</eventbox>
<variable>
"vNOTE"
</variable>
<input file>'$NB_PAGE'</input>
</notebook>
</'$BOX'box>
<hbox space-expand="false" visible="false" spacing="0">
<button relief="2"><input file stock="gtk-help"></input>
<action>Xdialog --title "MMview" --left --msgbox "'$HLP1'" x &</action>
</button>
<text space-expand="false" xalign="0" label="Shell: "></text>
<entry space-fill="true" space-expand="true" secondary-icon-stock="gtk-clear" secondary-icon-tooltip-text="Clear command line">
<variable>
"vCMDLINE"
</variable>
<input file>"'$COMMAND'"</input>
<action signal="key-press-event" condition="command_is_true([[ $KEY_VAL == 0xff52 ]] && echo true )">activate:vMENU_VIEWHISTORY</action>
<action signal="secondary-icon-release">clear:vCMDLINE</action>
<action signal="activate">activate:vMENU_F4</action>
</entry>
<variable export="false">
"vCOMMANDBOX"
</variable>
</hbox>
<hbox space-expand="false" margin="'$STATUS_MARGIN'" visible="true">
<entry space-expand="true">
<variable>
"vSTATUSBAR"
</variable>
<input>fill_statusbar</input>
</entry>
<button label=" Quit ">
<variable export="false">
"vBTN_QUIT"
</variable>
<action>lastrites_save</action>
<action>lastrites_cleanup</action>
<action>exit:OK</action>
</button>
</hbox>
</vbox>
<vbox visible="false">
<text><variable>vTSTART</variable><input>date +%s%2N</input></text>
<text><variable>vDURATION</variable><input>echo -n $(($(date +%s%2N)-vTSTART))</input></text>
</vbox>
<variable>MAIN_DIALOG</variable>
<action signal="show">disable:vMENU_F4</action>
<action signal="delete-event">lastrites_cleanup</action>
</window>
'
}
exec -a MMVprocess gtkdialog
Tips & Tricks

Tips & Tricks are simple little actions you can take to make your life easier when using Puppy. You will probably know most of the tips but there are always new users that don't.

find - smokey01
find

The find command by smokey01

There are many utilities available to help you find files on your computer but some are much better than other.

One of the best command line tools is the find command.

To get help, type: find --help in a terminal.

If I'm looking for a file all I normally do is type: find -name filename on the drive that I wish to search.

You can also use wildcards like: find -name filename* or *filename*

Remember in Linux, Linux is different to linux. Upper and Lower case is different.

If you can't remember if the filename has upper or lower characters then use: find iname filename instead.

Useful Links

Puppy Linux Forums USA

Ibiblio repository USA

nluug repository Netherlands

Internode repository Australia

University of Crete repository Greece

aarnet repository Australia

Internet archive repository USA

Puppy Linux Tips by smokey01

Puppy Linux wikka Puppy sites

Bookmarkos provided by kerl

Search the Puppy Linux Forums

Barry Kauler's News Blog

labbe5 Report

https://www.opendesktop.org

Puppy Linux Icon Sets

http://lxer.com/

https://distrowatch.com/

https://www.linux-apps.com/

SecurityBaron.com


Contributors this month

Not all of the people below have physically given me the information to publish. If I find information I will give the credit where it is due. So if you see your name on the list below please don't be alarmed or upset. You are receiving the credit you deserve.

smokey01
kirk, jamesbond & the Fatdog team
mistfire
gjuhasz
Barry Kauler
Terry Schuster
MochiMoppel

Proof reading - russoodle

Newsletter Information

Display tip:
To improve the Notecase display format please press F7 then:
- Tick the "Restore last position/size" checkbox.
- Select the "Display" tab and tick "Wrap text".

Newsletter index written by 6502coder can be found here:
http://www.murga-linux.com/puppy/viewtopic.php?p=945962#945962

Contributions

If you have information you would like to see in the newsletter please email it to smokey01 at smokey01@internode.on.net. I prefer it to be created in Notecase otherwise it makes my job a bit more difficult. I don't intend doing any significant editing but I will attempt to read all of the articles and ask a couple of others to do some proof reading. If you would like to assist in proof reading please let me know on the email address above.

Notecase is very easy to learn and use. Try and keep your articles to less than 1000 words. Photos and images should be no bigger than 1024 x 768. I can always make them smaller.

The deadline for articles is the 20th of each month. Let's not worry about time zones. I know it may be the 20th in Australia and only the 19th in the USA but I can live with this. If it's more than 24 hours late with respect to Australian CST then your article may be pushed right, into the next edition. I expect proof reading to take less than a week which will provide about four days to publish at the beginning of each month.

I will upload the Newsletter to my site at http://smokey01.com/newsletters. There will be two versions. One will be an xz compressed Notecase file and the other will be a html file so it can be read in a browser.

I have changed the original naming convention to 0001-PuppyLinuxNewsletter-Jan2017.ncd.xz and 0001-PuppyLinuxNewsletter-Jan2017.html respectively. The formatting of the html is not brilliant but readable. The newsletter is intended to be downloaded and read in Notecase.

Disclaimer

The editor has the right to veto any articles that he/she considers inappropriate. A reasonable effort will be made to avoid spelling and grammatical errors however, I'm sure some may slip through. This newsletter is published by volunteers, and is free, so please be kind. Constructive criticism and positive suggestions are welcomed.

smokey01