objects

Menu

Monthly Archives: August 2013

It is mostly about the icons used in the desktop metaphor, to represent apps and the documents that apps create/understand.

This blog is a log of many websites I visited, tilting at windmills, trying to make sense of ever changing chaos.

App icons defined

App icons are a set of icons (AppIconSet) that represents an app and its documents to a user of an OS that uses the desktop metaphor.

An AppIconSet can be an improper set: having only one image. The same image CAN be used for AppIcons and MimeTypeIcons. A user can usually distinguish the two uses: in one use the icon has the app name beneath it, and in the other use, the icon has a document name beneath it. This gets into politics, when an app and the mimetypes it creates are proprietary, the same icon could be used, but once the mimetype becomes a standard, one app should not put its icon on documents.

Icon meaning

In this context, an icon as a displayed image means a bitmap image, and a smallish one, a few centimeters, and a few tens of pixels in resolution. Icons as displayed may be generated from vector graphic images. It is important to distinguish icon as a source file of displayed images. This post itself does not always keep the distinction clear.

A quick summary is: modern OS’s and their desktops need a scaleable image as a source file of displayed image icons. That is, SVG is built into the OS and desktop. ‘Modern’ means in the last few years. SVG in KDE describes KDE’s new support for scaling icons.

User Interface Guidelines

These documents are mostly about graphic designing icon images, with some mentions of responsibilities for app installations.

These are subclasses in the sense that the behaviour is different, at least to a user, if not to a programmer.

In this document, I use app icon to mean AppIcons and MimeTypeIcons: the installation of a document viewing or editing application is often responsible for both (when an app establishes its own mimetype.) But I am excluding WidgetIcons, the icons that an app uses internally, that is, the icons that an app provides as resources for its own toolbars, sidebars, and other widgets.

AppIcon and MimeTypeIcon images can share drawing elements or motifs:

for branding purposes, in the case of proprietary apps

as a user interface strategy to show relations between an app and the documents it creates or understands

For example, the same motif of a music note can appear in related AppIcon and MimeTypeIcon.

App icons and GUI Frameworks e.g. Qt

It is NOT the responsibility of the framework to provide FreestandingIcons; that is the responsibility of the packaging.

In Qt, QWindow.setWindowIcon() puts a ToolbarIcon in the window’s title bar. This is for main (top) windows only, so that in an application that has many top windows, a user can know which app the window belongs to? This is the responsibility of the app. This is optional, since the text of the titlebar may serve the same purpose?

Qt has other functions for getting WidgetIcons, including ‘standard’, cross-platform icons, and themed icons. (Beyond the scope.)

App icons as sets

OS’s usually require OR allow (of a program to be installed) a set of icon images, at different resolutions (and corresponding use in different displayed real sizes.)

It would be nice if an OS required only one icon image and generated displayed icon instances of different resolutions. To some extent, this is possible.

However, to algorithmically generate low resolution images, i.e. icons or thumbnails, from high resolution bitmaps, is a hard problem in computer graphics algorithms. (Search under “summarizing visual data”.) Also, much has been written (enough to clog the search for the topic of this post) about how to manually create an icon set of bitmaps, tweaking pixels of each icon.

It is NOT so a hard problem to generate low resolution bitmap images from scalable images, and this is what modern OS and desktops do.

OSX accepts icons in PDF and generates icons of higher resolution from them.

The Freedesktop org spec for icon themes also specifies (vaguely) how to use scalable graphics for icons.

The requirement for a set (of displayed bitmaps) is a user interface design issue:

freedom for users to choose a size

comfort for users, when higher resolution and larger size lets them recognize an icon (it fails as an icon if the user doesn’t recognize it.)

The requirement for a set is also a business and software system issue:

provided as a service at installation time by a software package to a package manager client

provided as a service by a package management system to desktop browser clients

Who is responsible for creating the set, especially from a single scalable image? Recently, the answer has become: the OS and desktop are responsible for generating the set from a scalable image that you provide in the install package.

Vector graphics and icons

Scaleable vector graphics (SVG and PDF formats are both scalable) scale without loss of resolution. However, an SVG and PDF file may contain (embed) a bitmap image that won’t scale without loss of resolution. When a spec for icons says scalable graphic image, do they mean one with embedded bitmap? I don’t think so.

When a spec for icons says a scalable graphic image of a certain size (say 64×64) , why the size requirement? I think that is overspecifying. After all, scalable means it can be rendered in any size.

What size icons does each Linux platform require in an icon set? Icon Themes

Debian is not concerned with AppIcons. They are only a concern of desktops.

The Freedesktop organization document entitled “Icon Theme Specification” defines the minimum requirements. It is a ‘pseudo’ standard, a convention.

A user thinks of a theme like a graphic designer, and that document is largely about that kind of ‘theme’. But the document describes a ‘default theme’ (name ‘hicolor’.) An IconSet is a component of a theme, so this document describes the minimum requirement for app icons:

So, you’re an application author, and want to install application icons so that they work in the KDE and Gnome menus. Minimally you should install a 48×48 icon in the hicolor theme. This means installing a PNG file in $prefix/share/icons/hicolor/48×48/apps.

But it also vaguely talks about SVG files in this and other directories.

But the two competing desktops: Gnome and KDE, and value-adding distributors such as Ubuntu, may have further requirements.

The different sizes are used by different utility apps of the desktop (Launcher, Dash, Ubuntu Software Center, Nautilus). But this doesn’t mean you as a packager must provide the icon set.

(I don’t know where a requirement is strictly specified.)

A brute force strategy for creating an icon set

If your goal is: a crude AppIconSet that works on most Linux platforms, even older distributions, then you can adopt this strategy:

create a scalable image that is is very simple, an outline and contours, black and white image

generate the set of icon bitmaps in resolutions (sizes) that covers all the platforms: 16, 22, 32, 48, 64, 128

put those icons in your package

You can use Inkscape for both creating the scalable and bitmap images.

You might use this strategy if you are very concerned about the quality of your displayed icons.

A simple, modern strategy

If your goal is: the minimum work on your part to get some icon representing your app on the desktop:

create an SVG image (e.g. using Inkscape).

put that image in the default icon theme at /usr/share/icons/hicolor/scalable

The units and value of the size of the SVG image doesn’t seem to matter, but at least in Inkscape, the size DOES matter in this way:

your drawing should fill the size and be contained in the size

the shape should be symmetrical (e.g. a square or a circle)

(I think this is a flaw of Inkscape or the OS that displays the SVG as an AppIcon: the size of the area that the drawing elements cover (the bounding rect) should be determined at rendering time, not specified in the SVG.)

About Automating

This note is about automating: making the Debian package install your mimetype when a user installs.

This is for a shortcut packaging done by you for limited distribution. If your app is in the main distribution channels (Debian or Ubuntu) than a packager person might be doing this for you, in a different way.

The web is clogged with posts telling user’s how to fix mimetype icons manually (when installing an app fails to do it automatically.) Those posts are relevant.

About Registering with the IANA

I don’t know the benefits of registering your mimetype with an international standards organization. I presume you may just start using a new mimetype, and register it when it becomes popular. You might want to search the IANA site to see whether your mimetype is truly new (not registered by someone else.)

About mimetypes and file extensions on Linux

A mimetype is a Type in the object oriented sense. A file instance has the type, meaning the file behaves a certain way under certain operations (mainly, reading by the owning application.)

The fact that the file has a certain type is not necessarily:

labeled on the outside of the file, in the filename extension e.g. ‘.bmp’

nor in a header in the contents of the file (e.g. first three bytes ‘BMP’)

nor in separate metadata (resource fork?) associated with a file.

Linux actually uses a combination of those to determine a file’s mimetype. Other OS’s differ.

The process

define a mimetype: tell the OS how to recognize files having the mimetype

associate an icon: tell the OS what icon to display for said mimetype

register your application for the mimetype: tell the OS desktop what application understands the mimetype (what app to launch when a file is clicked.)

For this example:

application name: ‘helloworld’

file extension: ‘.hlw’

mimetype name: ‘application/hlw’

Define a mimetype

In your Debian template directory create: /usr/share/mime/packages/helloworld.xml. (This will be copied to the computers’s filesystem at install time.)

(The name need not be helloworld.xml, as long as it is unique. The OS reads all the XML files in this directory, no matter what they are named. The contents of the XML file must match the mimetype. It might be that the suffix of the file need not even be .xml, since the mimetype of the file: text/xml, might be determinable by the function in the OS that is reading them even without the suffix.)

‘.hlw’ is a filename extension that helps the OS recognize files having the mimetype

The second half of the mimetype name need not match the filename extension, but it usually does? There might be other ways to get the OS to recognize files having a mimetype, for example, patching the algorithms used by the OS. (Beyond the scope of this tutorial.)

Here, you might be able to substitute for ‘application’, for example ‘image’ or ‘text’. The word ‘application’ might imply that the file is binary versus text? If the OS thinks your file (before creating the mimetype) is of mimetype ‘application/octet-stream’? (Beyond the scope of this tutorial.)

If you are doing this manually, create this file then run the command ‘sudo update-mime-database /usr/share/mime’. But the installer should trigger this automatically at install time (or at computer restart.)

Associate an icon

Now associate an icon with the MIME type. Create an SVG icon. Name it “application-hlw.svg” Note that the name of the file matches the mimetype name with slashes replaced by “-” and there are no capital letters.

Put the file in this directory in your Debian template directory:

/usr/share/icons/hicolor/scalable/mimetypes/application-hlw.svg

Here, hicolor is an icon theme, the default one for both Gnome and KDE. (Beyond the scope of this tutorial.)

Register your application for the mimetype

In your application’s desktop file at the following location in your Debian template directory:

The LGPL lets your proprietary app use LGPL libraries as long as you (among other things) let users ‘recombine your software with modified libraries.’ The LGPL says you must provide ‘object code’ for your app. (So users can keep using your proprietary software even as the libraries are improved, by bug fixes and other improvements. So your proprietariness is not impeding progress in the libraries: users won’t be motivated to improve the libraries if they can’t use the improvements in their context.)

What if your app is interpreted Python, packaged with PyInstaller (or other freeze tool?)

your app’s .pyc files ( ! it doesn’t use the .py, this is a gotcha for naive PyInstaller users)

(What follows is supposition…)

Then you meet the terms of the LGPL since the way that PyInstaller bundles is well documented. A motivated user could ‘recombine’ your software with modified libraries, by punching the libraries out of the PyInstaller bundle and filling the hole with new libraries. Or equivalently, extracting your proprietary object code and relinking (re-PyInstaller-ing) it with updated LGPL libraries. I’m not sure what tools are available to do it, or whether the LGPL requires a tool to be available. It might be that the LGPL requires you to ‘convey’ your app’s proprietary code as a directory tree of .pyc files?

In this case, both the executable LGPL libraries and the LGPL .pyc modules are ‘object’ files as defined by the LGPL.

Your proprietary code in the bundle is .pyc, which can be reverse engineered (but so can proprietary object code that is compiled real machine code.) Distributing a directory tree of .pyc goes a long way in revealing your proprietary object model. About the only ‘information’ omitted from they object .pyc code are the docstrings and other comments, which probably include your tests (which are a redundant specification of your program.)

protects your copyright and fulfils some of your obligation under GPL and LGPL

The goal is NOT a package that the Ubuntu or Debian organizations will necessarily accept for distribution. In particular:

it will be missing the changelog.

those organizations might prefer a traditional Linux packaging not using PyInstaller (and therefore smaller in size.)

those organizations prefer free software

Flaws in this post

This post is a work in progress… these things don’t work:

the copyright file in the debian input directory doesn’t work using these methods

When you click on the .deb package the installer opens and offers to install, or reinstall, and does succeed in installing. However, later the installer (e.g. Ubuntu Software Center) fails to recognize the installed app IS installed (fails to offer to remove it).

Tools

They are available free. Just try to use them: if they are not installed, you will get a message that tells you how to install them. Use your package manager (e.g. Ubuntu Software Center, or apt-get) to install them.

What the Debian packager does

The packager reads a directory of files ( the ‘input directory’) and produces a single package file ( .deb) which an package manger (installer) will read to install your app.

So the larger ‘packaging process’ is mostly creating the input directory.

The structure of the input directory

The input directory contains:

a subdirectory (DEBIAN) that controls the packager (also called metadata: data about your app)

a subdirectory (e.g. usr/share) that is a template of the installation on the target computer

Naming a package

Example input directory

helloworld_1.0-1/
helloworld_1.0-1/DEBIAN
helloworld_1.0-1/DEBIAN/control
helloworld_1.0-1/usr/share/bin/helloworld.exe
helloworld_1.0-1/usr/share/applications/helloworld.desktop
helloworld_1.0-1/usr/share/mime/packages/helloworld.xml
helloworld_1.0-1/usr/share/icons/hicolor/48x48/apps/helloworld.png
helloworld_1.0-1/usr/share/icons/hicolor/scalable/apps/helloworld.svg
helloworld_1.0-1/usr/share/icons/hicolor/scalable/mimetypes/application-hlw.svg
helloworld_1.0-1/usr/share/pixmaps/helloworld.png ** I think this is unnecessary, a fallback for older versions helloworld_1.0-1/DEBIAN/copyright ** Currently I can't get this to be recognized by dpkg-deb

Explanation of the example input directory

The DEBIAN subdirectory controls the packager.

Everything else below the root is a template. (After your app is installed, all those files will exist on the target computer.)

In this example, there is only one executable file (…/bin/helloword.exe) since PyInstaller has hidden (bundled, or put in a self-extracting archive) the dependencies.

The control file

Package: helloworld
Version: 1.0-1
Section: Applications/Graphics
Priority: optional
Architecture: i386
Depends:
Maintainer: John Doe <jdoe@example.com>
Installed-Size: 10000
Description: Classic example program doing nothing important! (synopsis)
(Extended description) No dependencies or significant conflicts.
Each line starting with a blank is part of a paragraph.
This variation of helloworld creates a file with mimetype foo.

Note, ‘Depends’ is empty because PyInstaller has bundled the dependencies (subverted the usual Linux install strategy.)

Installed-Size is just an estimate, in kb, so a user can decide whether to install.

I think the architecture is i386 since PyInstaller includes a bootstrap loader compiled for this architecture? The architecture ‘any’ would be for pure Python and Java apps, packaged in a different, non-shortcut way.

Checklists

There is no concise document describing a Debian package checklist, but the lintian utility effectively defines the checklist.

Some documents say the Debian organization requires a man page, but lintian calls it a warning, not an error.

Note that errors are not necessarily fatal to an install. For example, I have an unstripped binary, but it does install.

Iterating

Repeat:

futz with the input directory (structure or content files)

build the package

check the package

Until lintian reports no errors (warnings are OK.)

Actually installing

In a file browser, double click on the .deb file. A package manager will start, for example Ubuntu Software Center.

Since this example is all about user-friendliness, you should do it this way (graphically) since that is what many users will do. It might reveal other errors.

However, alternatively, on a command line:

>sudo dpkg -i helloworld_1.0-1.deb

The installer (dpkg) installs your app (moves the components of your app from the package to their place in the file system, does other initialization of the installation.)

Errors in installation

In one of my tests, Ubuntu Software Center showed a warning dialog saying “The package is of bad quality” and giving details ‘The package doesn’t provide a valid Installed-Size control field. See Debian Policy 5.6.20.’ This for a package that had passed lintian (except for the copyright) and which dpkg invoked from the command line did not complain about.

The ancient sense of ‘install’ software

It’s not user-friendly. A user deeply understands the process of installing, and the OS. The user uses a command line in a terminal or console. The user downloads a binary and fiddles with system directories to copy the executable to some ‘bin’ directory. The name of the program file is the command to execute it. The app has no visual icon, no aliases.

Worse, ‘install’ could mean: download source code, compile it, and THEN install the binary. That’s not necessarily hard: it is often reduced to three commands: .configure, make, and make install. But that sometimes is a trip to ‘dependency hell’. And it often yields only a command line app.

The modern, user-friendly sense of ‘install’ software

an installer automatically starts, or starts when a user clicks on the downloaded ‘package’

your app will be “integrated with the desktop”, that is, have a clickable icon in the usual places.

the OS will remember how to uninstall the app

Self-installer

A file that installs an app. The file is executable, and usually clickable to run. A self-installer is both an ‘installer’ and a ‘package.’ As a file it comprises : an installer and the package it installs. When it runs, its installer installs the package (which may involve uncompressing and unarchiving the package as well as other installing subprocesses.)

An app has resources

Resources are non-executable objects that an app needs to run, for example images (icons, etc.) and sounds.

Resources are packaged with the executable of an app.

Resources needed for packaging include:

resources the app needs to run (run resources)

resource the installer needs to install the app (install resources), the most important of which is the ‘app icon’

For command line apps, install resources might include man pages.

More generally, install resources are the objects that a user and the OS expects for a ‘well-behaved’ program. What ‘install resources’ comprises, depends on the sophistication of the user and the OS.

PyInstaller is NOT an installer

No, despite its name (which has more to do with its historical roots), PyInstaller is used to transform a Python program into a native executable form which does not require existing Python installations to run. Building an installer program is totally outside the scope of PyInstaller.

PyInstaller produces a binary with no dependencies. A user can ‘install’ it in the ancient sense, but no in the modern, user-friendly sense. One goal of PyInstaller is to avoid ‘dependency hell.’

The Linux standard for well-behaved, desktop apps

For our purposes, the Desktop Entry Specification is pertinent. It is about how the OS presents your app to the user, or program shortcuts (clickable icons.)

The Debian standard for packages

The Debian community is concerned with Linux as a command line OS, not with the desktop metaphor.

The Debian Policy Manual specifies the standard, and there is no concise specification. You must read that document, looking for “package .*must have”. That document doesn’t always tell you the consequences (for installing) of failing the requirements. For example, it says if the man page is missing, it is considered a bug, but the package will still install.

Much of that document is concerned with version and dependency, that is, stuff a package manager needs.

Much of that document is concerned about ‘run resources’: bundling what the app needs.

The clear state has getter: count() <= 0, and setter clear(). (The getter method is not defined by Qt, but let’s name it “isClear”.)

“isClean” does not imply “isClear”. A clean undo stack may still have commands that can be redone/undone.

“isClear” implies “isClean.” A clear undo stack does not have any commands on it.

Typically, when you save a document (or open an existing one), you call clear(). At that point, your app behaves just as if the user newly opened the document: there is nothing to undo or redo.

Subsequently, if the user does something, but undoes it, the document is “clean”. That is, in the same condition as is saved. Typically, an app shows the unclean state in the title bar, for example by an asterisk in front of the document name.