To reply to a blog post, email me at Daniel_Burrows@alumni.brown.edu. Please let me know whether I should post your reply on the blog page.
It's been a long time since I wrote about aptitude-gtk. Mostly that's because I haven't been doing any work on it, due to a combination of several holidays, sickness and (last but certainly not least) an unfortunate relapse of WoW-addiction. But we have moved the ball forward since the 0.5.0 release. Some of the changes since then are just polishing, with no major changes in functionality, but there are a few things that are very visible:
Status pipe support
aptitude now supports the dpkg status pipe. This means that it can
display a progress bar showing how far through the install process it
is. In fact, if you are using the Gnome frontend for Debconf, you
don't even need to display the terminal at all, unless a package is so
uncouth as to prompt directly on standard input. I'd like to thank
the Synaptic developers -- although this is all my own code, their
implementation of this functionality was very valuable documentation
of how apt frontends use the status pipe in practice. Incidentally,
the aptitude implementation is modularized and available in
src/generic/apt/parse_dpkg_status.cc and
src/generic/apt/parse_dpkg_status.h. If you
want to parse dpkg messages in your own GPL project, you might want to
take a look at that code. And if I don't forget, I'll ask about
including this in apt once the lenny freeze is lifted. [0]
Here's the dpkg progress bar in action, showing that dpkg is configuring libmad0:
Clicking the "View Details" button on the dpkg progress bar will pop
up a terminal in a new tab; you can close the tab and dpkg will go
back to running in the background. And yes, I know that the progress
bar for the download shouldn't hang around after the download
completes. 
Searching for partial strings
As noted in the release notes for
0.5.0,
incremental searching from the curses frontend was broken by the 0.5.0
release. I've created a new match term named ?term-prefix which
matches against any extension of the term; for instance, searching
form
will find any package that matches
the term ?term-prefix(comp)
, the term compiler
, the term
computer
, or any other extension of compromise
. The
upshot is that incremental searching should work again.comp
Editing the list of visible columns
The current package list doesn't show very much information. That's deliberate: I don't want to clutter the default view with a lot of stuff that's only necessary from time to time. But until now, there was no way to change which columns were visible. Now there is:
This is a very rough proof-of-concept dialog that I've just checked into the source tree. The checkboxes are fully functional (clicking them shows and hides columns), but the buttons to save the current setup or to apply it to all the active tabs are not working. With this in place, we can think about creating columns for most of the interesting information about a package (archive, maintainer, etc).
[0] By which I mean, I'll say does anyone
object if I add this utility code to apt?
, and when no-one says
no
I'll commit it. 
Regarding the ballot currently before the Developers, Christian Perrier writes:
Moreover, the proposal is worded and was pushed in a way that all (but one) options that would allow us to release lenny will need a 3:1 majority, which is obviously very hard to achieve (and as, there are several such proposals, the vote will be spread out among all of them).
So, those folks who make the release of lenny their priority are now facing an interesting tactical choice: how the ..... should we vote for this to happen?
I personnally did choose to vote this way: 5462371.
I agree with Christian's goals, but in my opinion, the ballot he has cast actually makes less likely that the winning option will allow us to release lenny.
In Debian, we run a two-round election using a single ballot. In the
first round, any options that need a 3:1 majority must defeat the
default option by a 3:1 majority. Options which fail this test are
eliminated and dropped from further consideration. In the second
round, a winner is chosen from the remaining options using a
Condorcet method as usual. The upshot of this is that
the votes for the 3:1 majority cannot be spread out
, unless
people habitually place only one of the 3:1 options over Further
Discussion. Furthermore, voting everything below Further Discussion
benefits the options that don't require a 3:1 majority over the ones
that do.
For a real
example, let's say that we have a ballot like this:
[ ] Choice 1: Omelette [3:1]
[ ] Choice 2: Quiche [3:1]
[ ] Choice 3: Toast
[ ] Choice 4: Further Discussion
Suppose that we don't like the ballot at all, but we want an egg-based breakfast. What happens if we vote like this?
[2] Choice 1: Omelette [3:1]
[3] Choice 2: Quiche [3:1]
[4] Choice 3: Toast
[1] Choice 4: Further Discussion
This ballot can be read as: I don't think that omelettes or quiche
should pass the 3:1 majority requirement. But if they do, I prefer
them to toast.
Unless 75% of the remaining voters vote omelette and
quiche above toast, those two options will be thrown away, and the
vote will be determined by whether half the voters placed toast over
further discussion. If you want to make sure that toast doesn't win,
you have to vote (insincerely) like this:
[1] Choice 1: Omelette [3:1]
[1] Choice 2: Quiche [3:1]
[3] Choice 3: Toast
[2] Choice 4: Further Discussion
Sadly, there is no way to vote against the vote
without
effectively also voting for toast!
I wonder if it was a mistake to combine the supermajority vote and the Condorcet vote on a single ballot. Maybe it would be better to write both ballots out explicitly:
Some options on this ballot must be approved by a 3:1
supermajority of the electorate. Please enter 'Y' next to the
options that you approve of and 'N' next to those you disapprove
of. Ballot options on which 75% of voters vote 'Y' will proceed
to the next round (below).
[ ] Choice 1: Omelette [3:1]
[ ] Choice 2: Quiche [3:1]
Rank the ballot options below:
[ ] Choice 1: Omelette [3:1]
[ ] Choice 2: Quiche [3:1]
[ ] Choice 3: Toast
[ ] Choice 4: Further Discussion
That would allow people who want to vote against the vote
without privileging any of the options over the others to do so: vote
Y
to all 3:1 options, then vote 2221
on the rest.
On the other hand, I suspect people would be confused in different
ways by a voting system that was this complicated, voting Y
in
places where they should write a number and writing numbers where they
should write Y
or N
. I guess all this mess is why we
still use First Past the Post for votes in the real
world...
I've released version 0.5.0 of the aptitude package manager (release notes). Once the mirrors have synced, you should be able to download it from Debian's experimental distribution, or manually from the aptitude package page.
[Edit] This release was uploaded to experimental because it is not a final release. aptitude follows the Linux version numbering scheme in which an odd second digit indicates an unstable development version. DO NOT INSTALL THIS VERSION IF YOU WANT STABLE SOFTWARE; IT IS INCOMPLETE, INADEQUATE, AND PROBABLY INCORRECT.
To reply to some questions that several people have asked me:
The final release of aptitude 0.6.0 will be split into two packages, one containing only the traditional text interface and named
, and one containing the GUI binary namedaptitude-curses
, with both of them providing theaptitude-gtk
binary through Debian's alternatives mechanism. This release wasn't split because the code to drop GTK+ support was buggy and I discovered this fact halfway through assembling the release. It's fixed now.aptitudeTo run the traditional curses interface, pass the
--no-guicommand-line parameter or set the optionAptitude::Start-Guitofalsein/etc/apt/apt.conf. Unless you want to test that the curses frontend isn't broken, though, there won't be much for you in this release: the only change affecting it is Xapian support, and that currently breaks incremental search. (see the note above about this being an unstable release)
Also, another feature that I suspect might be bothersome is the
behavior of updating the package lists and downloading changelogs on
startup. There's no switch for changelogs yet, but you can disable
the package list update by setting Aptitude::Update-On-Startup to
false.
The main change in this release is the new GTK+ frontend, designed and implemented by Obey Arthur Liu with funding from the 2008 edition of Google's Summer of Code.
The new frontend is is an effort to bring some of the design principles of the curses frontend to a GUI environment, while also exploiting the unique features a GUI gives us and exploring ways to deal with changes in the environment in the nine years since aptitude was first designed. For instance, it is no longer reasonable for the user to actually read the entire package list (when I first installed Debian, you could read through the whole package list in a single sitting). So instead of basing the interface around a list of all the packages, we based it around the ability to search for the packages you're interested in.
This version of aptitude also introduces Xapian searching:
daniel@emurlahn:~$ aptitude search "apt package manager" i apt - Advanced front-end for dpkg p apt-dater - terminal-based remote package update manager p apt-dater-dbg - terminal-based remote package update manager (d i aptitude - terminal-based package manager i aptitude-dbg - Debug symbols for the aptitude package manager p createrepo - generates the metadata necessary for a RPM pack p gnome-apt - graphical package manager p smartpm - An alternative package manager that works with p smartpm-core - An alternative package manager that works with i synaptic - Graphical package manager i A update-manager-core - APT update manager core functionality
You might ask why I didn't search for just package manager
.
The reason is simple: aptitude doesn't yet sort by relevance, and that
second search gave me screenfuls of packages whose description
contains both package
and manager
, including addressmanager.app (a PIM for GNUstep), compiz-gtk
(a piece of eye candy), and wterm (an X terminal
emulator). However, it is worth noting that Xapian searches are fully
integrated into the aptitude search language, so they can be combined
with non-Xapian search terms in just the way you would expect:
daniel@emurlahn:~$ aptitude search "?installed apt package manager" i apt - Advanced front-end for dpkg i aptitude - terminal-based package manager i aptitude-dbg - Debug symbols for the aptitude package manager i synaptic - Graphical package manager i A update-manager-core - APT update manager core functionality
So, all the basic functionality that the GUI version needs is in
place; the next step is to start polishing it and filling in the gaps
that are left. And, of course, suggestions and bug reports are
welcome, so we know where the rough spots and the gaps are. Please
send your comments to aptitude-devel@lists.alioth.debian.org so that
they are part of the public record and so that people besides me can
read them. 
Happy package managing!
Posted Tue Nov 11 22:56:00 2008I got several emails in reply to my previous
post on representing Sudoku problems as
package dependencies. Several people asked about the algorithm that
aptitude uses to solve these problems. A
slightly out-of-date discussion package management and the aptitude
algorithm can be found at
http://people.debian.org/~dburrows/model.pdf. One question was
interesting enough to deserve a follow-up blog post: Wolf T.
referred to the page http://norvig.com/sudoku.html and asked how
long it would take aptitude aptitude to solve the hard Sudoku problems
on that page. He suspected that aptitude would do basic constraint
propagation and then be forced to exhaustively search all the possible
solutions to the problem.
In brief: the answer is that it doesn't work by default, but not for the reason he suggested, and you can make it work with a few command-line arguments. In order to try this out you'll need a new version of the Sudoku reducer that can parse the problems on that Web page: debsudoku2.py.
If I do a straight conversion of one of those problems and then run it through aptitude, it goes spinning off and never comes back. But aptitude is coded to avoid exhaustive searches; otherwise it couldn't solve dependency problems in reasonable amounts of time. In this particular situation, though, aptitude is clearly performing an exhaustive search; here's one series of status outputs:
open: 5124; closed: 4993; defer: 0; conflict: 374 Resolving dependencies... open: 10090; closed: 9942; defer: 0; conflict: 398 Resolving dependencies... open: 14726; closed: 14888; defer: 0; conflict: 440 Resolving dependencies...
Here open
is the number of partial solutions that aptitude
wants to examine, and closed
is the number that it's already
examined. aptitude isn't making progress here and it isn't finding
solutions; in fact, it's creating, on average, about two new partial
solutions for every one it examines.
Why is aptitude doing this? Its resolver isn't a brute-force
algorithm; in fact, it looks remarkably like the Sudoku solver
discussed at http://norvig.com/sudoku.html. On each step, aptitude
takes a partial solution, picks one dependency, and resolves it by
installing or removing a package. This is pretty much equivalent to
filling in one not-filled-in cell; in fact, in the conflicts
Sudoku reduction, it's exactly equivalent.
There is one difference, though, and it stems from a difference in the problem domains of Sudoku and package management:
Not all dependency resolutions are created equal.
In Sudoku, any solution to the puzzle will do. Not so in package
management; solving
a dependency problem by removing every
package on the system will produce a formally correct answer and a
very unhappy user. Even results that are not utterly disastrous could
be annoying to the user, so the resolver needs to somehow aim for
good
answers.
The page on Sudoku solvers suggests sticking to whatever value you placed in a cell, unless that doesn't lead to any solutions at all. This is technically known as a depth-first search. The problem with taking this approach when resolving package dependencies is that an apparently safe choice can end up requiring undesirable actions later on (like removing large swathes of the system). For this reason, aptitude tries to strike a balance between sticking to its current line of reasoning, and abandoning it when it seems to be turning out badly (this makes it a form of best-first search).
On typical Debian archives, the package relationships are simple enough that it's OK if aptitude does this from time to time; it makes the search a little more thorough (thus costly), but the ability to back out of questionable branches is very valuable. But it looks like when aptitude is applied to Sudoku puzzles, it has trouble settling on a single series of choices. It keeps thinking that the solutions are getting worse, so it backs up and tries another branch, but they don't look any better over there, so it backs up and tries another branch, and so on.
The option Aptitude::ProblemResolver::StepScore sets how hard
aptitude will try to stick to the same line of reasoning. Its default
value is 70, which is reasonable for package archives, but turning it
up to a large value such as 10000 will cause aptitude to use a
straight depth-first search, just like the Sudoku page recommends:
$ aptitude -s -o 'aptitude::problemresolver::stepscore=10000' -o 'aptitude::auto-install=false' install puzzle
Setting auto-install to false is a workaround for another odd
corner case/bug that happens to bite this Sudoku problem: for
technical reasons, doing this lets aptitude know that it should avoid
solutions that cancel the installation of puzzle. Otherwise you have
to sit there telling it no
for a bunch of solutions you aren't
interested in. Future versions of aptitude will probably provide a
way to explicitly give hints to the resolver.
With these options, aptitude was able to solve the hard
Sudoku puzzles that I gave it in anywhere from fifteen seconds to a
minute and 47 seconds. In contrast, the straight Sudoku solver does
30 problems in a second. Why is aptitude so slow? Based on skimming
debug traces and looking at the run-time behavior, I conjecture that
there are several reasons:
The aptitude search algorithm is very heavyweight. In the case where it takes over a minute, it only actually examines about 5,000 possible solutions. I don't know exactly where all this time is going, but I do know that the resolver does a lot of work on each step, for instance to try and detect dead ends that it hasn't reached yet. This is the
conflicts
counter that appears while the resolver is running. This pays off tremendously in terms of allowing aptitude to skip huge amounts of work (it may be why aptitude can solve Sudoku puzzles at all!), but it means that the resolver takes a long time for each potential solution it looks at.The Sudoku page suggests taking the cell with the fewest number of possible entries as the choice. I distinctly remember writing code to do this in aptitude, but it looks like I threw it out at some point or never committed it. I don't see why it should be any worse than the current approach, though (which is to pick an arbitrary dependency); maybe it just got misplaced at some point. Implementing this behavior decreased the time required to solve one puzzle from a minute and 45 seconds to just under a minute; I've committed this change to the post-lenny branch.
The Sudoku resolver has the advantage of being able to very quickly identify illegal
moves
. aptitude's resolver canlearn
this information, but it takes time and it can't apply Sudoku-specific optimizations. For instance, the Sudoku solver knows exactly which values can be placed in a given cell at any time. aptitude has to actuallyconsider
each of the cells that's available as a possibility and prove to itself that, e.g.,4
and6
can't be written in the same cell at the same time. And although it canlearn
this information, it takes time to do so and it takes time to see whether any of the past conflicts that itremembers
are present in a given solution.
As I noted above, I've already checked in one change to the resolver's
behavior. It might also be worth seeing what happens with a massive
increase in StepScore, so I've pegged it at 10000 on my computer
to see whether the results I get are noticeably worse.
The third item above -- the fact that aptitude needs to do more work
to understand which packages can't be installed -- is interesting.
The Sudoku solver is very proactive about this: it keeps track at all
times of which cell values are legal, and updates these sets every
time it transitions. In contrast, aptitude constantly re-checks all
the possible moves
it could make to see which ones are
currently legal.
I think that the resolver's speed could be boosted a little by doing the following:
Cache the currently legal solutions of each dependency at the time it's inserted into the queue.
When a new search node is generated by resolving a dependency, drop the formerly legal
moves
that are knocked out (for instance, by installing a different version of the same package).Come up with a quick way of re-testing new conflicts (the global list of dead-ends) so that search nodes that are already in the queue can be checked against the conflicts that were added since they were queued.
These changes won't make aptitude able to solve problems that it couldn't solve before, or at least not very many of them, but they should make the resolver faster on every problem it encounters. However, I don't think I want to actually implement them. It would be tricky to confirm that the resolver got faster on real dependency problems (since it's normally almost instantaneous), the changes would make the resolver code more complex and fragile (less readable, less maintainable), and there's a real chance of breaking something. Unless there are cases where the resolver is currently too slow on real package archives that don't involve an exponential blowup, I'm going to shelve the idea for now.
Posted Sat Aug 23 11:15:00 2008Update: There are more notes on how aptitude performs as a Sudoku solver here.
Russell Coker recently wrote a post entitled Ownership of the Local SE Linux Policy. This post has nothing to do with the substance of his post, which is a discussion of how distributions should configure SELinux by default. I know nothing about SELinux, but something that Russell said in passing caught my attention:
I am not aware of the Debian package dependencies (or those of any other distribution) being about to represent that the postfix package depends on selinux-policy-default-postfix if and only if the selinux-policy-default package is installed. Please note that I am not suggesting that we add support for such things, a package management system that can solve Sudoku based on package dependency rules is not something that I think would be useful or worth having.
(emphasis added)
As it happens, a little-known fact about the Debian packaging system is that you can, in fact, describe Sudoku puzzles in it!
Note for the impatient: If you want to skip all this talk and jump to the code, see debsudoku.py.
For those of you who, like me, are not Sudoku-heads, here's a quick
summary of the rules (for the common case of a game with 3
blocks
):
- The game is played by filling in a 9-by-9 grid with numbers between 1 and 9, inclusive. The board is divided into 9 3-by-3 blocks of grid cells in the obvious way.
- All the cells in a column must contain different numbers.
- All the cells in a row must contain different numbers.
- All the cells in a block must contain different numbers.
There are many ways that you could convert a Sudoku problem into a
Debian package archive, but here's a particularly simple one that is
close to my summary of the rules. Create 9 * 9 * 9 = 729 packages,
named cellR.C-V where R stands for row, C for column, and
V for value. Each of these packages represents writing the value
V in the cell (R, C). To describe the relationships of each
cell to the other cells in the problem, we can create several virtual
packages:
The virtual package
cellR.Crepresents the statementThe cell (
It will be used to ensure that only one value is placed in any particular cell, and to ensure that all the cells in the puzzle are filled in with something.R,C) has been filled in with some value.The virtual package
blockR.C-Vrepresents the statementA cell in the block (
The blockR,C) has been filled in with the valueV.coordinates
are the block-row and block-column containing the cell; for instance, the cell at (5, 8) is in block (2, 3). This package will be used to ensure that only one cell in a given block contains the same value.The virtual package
rowR-Vrepresents the statementA cell in the row
It will be used to ensure that no two cells in any given row have the same value.Rhas been filled in with the valueV.The virtual package
colC-Vrepresents the statementA cell in the column
It will be used to ensure that no two cells in any given column have the same value.Chas been filled in with the valueV.
Converting these requirements to package dependencies is quite
straightforward. For the package cellR.C-V, in block row BR and
block column BC, we add these lines to the package's definition:
Provides: cellR.C, blockBR.BC-V, rowR-V, colC-V
Conflicts: cellR.C, blockBR.BC-V, rowR-V, colC-V
For instance, the cell at (5, 8) will get these provides/conflicts for
V=2:
Provides: cell5.8, block2.3-2, row5-2, col8-2
Conflicts: cell5.8, block2.3-2, row5-2, col8-2
This relies on the fact that self-conflicts are ignored (see Debian Policy section 7.4).
To actually describe the puzzle we want to solve, we need to add another package that requires two things:
- Every cell contains a value.
- The cells that the problem fixes have their fixed values.
For instance,
Package: puzzle
Depends: cell1.1, cell1.2, ..., cell5.9-3, cell6.1, ....
if we want to require that the cell at (5, 9) contains the value 3.
Proof-of-concept
As a proof-of-concept, I have written a hacky Python script, named
debsudoku.py, that can convert
ksudoku saved games into Packages files suitable for use with
apt-get or aptitude. In fact, it has two modes: conflicts
,
which implements the conversion described above, and depends
,
which implements a different but logically equivalent conversion using
only Depends instead of Conflicts. To use the script, save a ksudoku
board without doing any work on it, then run
python debsudoku.py /path/to/the/ksudoku/board
I've only done minimal testing on this, so don't use it to fly airplanes (in fact, please don't use any Sudoku player to fly airplanes), but I did use it, in combination with aptitude, to solve a single ksudoku puzzle.
Real-world evaluation
Interestingly, in a test with an easy puzzle generated by ksudoku,
aptitude was able to solve the puzzle in just a
few seconds when it was expressed with the conflicts
reduction,
but failed to find a solution at all using depends
(I stopped
it after several minutes).
I think this is due to how the depends
reduction is performed.
Take rows: instead of generating conflicts between cells in a row, it
requires that each row contain every number between 1 and 9. The
problem with this is that aptitude's resolver functions poorly when
there are non-obvious conflicts in the dependency structure. It will
decide to try a combination of packages that can't be installed
together, but it won't realize it. As a result of this, it ends up
trying many possible combinations of packages. For instance, it might
try to place the number 3 in both (2, 5) and (5, 5). There is no
dependency outlawing this in the depends
reduction, so aptitude
will happily continue trying to resolve dependencies. Since it has
used 3 twice in the fifth column, it will not be able to find any way
to resolve all the dependencies that state that all the numbers
between 1 and 9 appear in the 5th column
, but it lacks the
higher-level reasoning that would allow it to break out; it will end
up trying many or most of the possible ways of filling cells in before
it gives up on the offending re-use of 3.
Luckily, real-world package archives (what the aptitude resolver is designed to run on) don't usually look like this.
Posted Tue Aug 19 22:23:00 2008I've thought on and off that it would be nice for the graphical version of aptitude to have decent hyphenation. Word-wrapping descriptions looks OK, but when the text area is thinner than the entire screen, it can look a little ragged on the right-hand side. For instance, take this rendering of the description of the toy program bb:

Not too bad, but if I render it in LaTeX, here's how it comes out:

Of course, for very thin text columns (and the above is arguably pushing it), hyphenation and text justification aren't what you want. But it would be nice to be able to at least see what it looked like.
Figuring that GTK+ might have some support for this, I delved into Google. I found this:
Line breaking
Line breaking adds additional layers of complexity. For one, all potential line breaks must be identified, including discretionary hyphens for Latin scripts, and word boundaries in (???). Secondly, inserting hyphens may require reshaping. Third is the line breaking algorithm itself, which may be nontrivial.
-- Pango 0.1 proposal, Raph Levien, 1999
and this:
Future plans for Pango include support for high quality printing, better hyphenation support, full justification, and the ability to handle vertical text such as Chinese and Japanese.
-- Pango: Text handling for the World, LWN (Forrest Cook) 2001
and also this:
I've been working on code to do hyphenation, hopefully to add to Pango. My new code is faster than libhnj and groff and uses less memory.
-- Hyphenation Design (Was Re: Possible Pango 1.4 ideas), Damon Chaplin, post to
org.gnome.gtk-i18n-list.
But no sign that any work has been done on hyphenation recently. 
The one intriguing thing I noticed, although it's not GTK+ at all, was
the libhyphen0 library, which might be useful.
Unfortunately, it's a bit more complicated than just flipping a switch
in GTK+: the library is documentation-free
, so to figure out
how to use it I'll need to read through its source code and deduce the
expected interface from that. Meh. Probably something to stick way
at the bottom of the priority list.
I've released version 0.4.11.9 of the aptitude package manager (release notes). This release incorporates a few trivial bug-fixes that I hoped to get out before the lenny freeze, but real life intervened. More importantly, it includes the fix for bug #483459, a non-fatal but highly annoying bug that affected Polish users. I hope the release team allows this one into lenny after it's been tested in unstable, but we'll see. I'll put in a formal request for an exemption once the new release has steeped a enough.
Posted Mon Aug 11 20:44:19 2008Late last year, I spent some time disentangling aptitude's internal UI library and packaging it as a separate library, which I named cwidget. This article is the first in what will hopefully become a series describing the basic concepts and APIs of cwidget. It applies to the versions of cwidget currently available in Debian sid and lenny, 0.5.11-1 and 0.5.12-1. Autogenerated documentation of cwidget can be found here (but beware that as of this writing it is somewhat incomplete).
In this tutorial, I will walk through a simple program (hello.cc) that initializes cwidget, displays a simple message box, and then terminates the program when the user confirms the message. I assume a basic familiarity with C++.

The first thing to do is to include the portions of cwidget that our
program will use. Most importantly, we need the top level
cwidget routines. These are the global routines
that initialize cwidget, shut it down, and control its main loop
(among other things).
#include <cwidget/toplevel.h>
cwidget comes with a collection of stock dialog
boxes
for things like displaying messages to the user. To access
the routines that build these dialogs, we write:
#include <cwidget/dialogs.h>
All the symbols provided by the cwidget library are in the cwidget
namespace. Using the full library name means that there's a
reasonable chance that its names will not conflict with the names
provided by other libraries; however, it's a real pain to type
cwidget over and over. Since this is the only namespaced library we
are using in this program, it's handy to define cw as an alias for
cwidget:
namespace cw = cwidget;
Now we're ready to write the main routine. The first interaction of client code with the cwidget library is to initialize it. This will initialize the ncurses library and put the terminal into a mode suitable for a full-screen curses program.
cw::toplevel::init();
Next, we create a dialog box that will be displayed to the user. There are two things to note about this code:
cwidget is Unicode-aware and the
ok()routine expects the message string to be a wide-character string. In this case, that means that we need to pass in a wide-character string (indicated by typing
in front of the string).LThe second argument tells cwidget what to do when the
ok
button is pressed. The expressionsigc::ptr_fun(cw::toplevel::exitmain);creates a slot using libsigc++. Briefly, a slot is a reference to a function or to a method of a class instance. When invoked, this particular slot will call
cwidget::toplevel::exitmain(), which causes the main cwidget loop to exit. The slot is wrapped incwidget::util::arg, a utility function that handles passing slots as optional arguments.
cw::widgets::widget_ref dialog = cw::dialogs::ok(L"Hello, world!", cw::util::arg(sigc::ptr_fun(cw::toplevel::exitmain)));
Now that we have a widget, the next step is to arrange for it to
appear on the terminal. In cwidget, control of the terminal is
assigned to a single top-level
widget: whatever it displays is
what gets displayed on the terminal, and all user input is passed
directly to it. In a real program this widget will typically manage a
collection of sub-widgets and assign each one a screen region, but for
now let's just display the dialog box we created:
cw::toplevel::settoplevel(dialog);
With everything initialized, we're ready to start the main loop.
mainloop() will keep the display up-to-date and dispatch incoming
events (for instance, keystrokes and mouse presses) until exitmain()
is invoked.
cw::toplevel::mainloop();
When the user presses Enter or clicks on the Ok button in the dialog,
exitmain() will be invoked by the binding that we set up earlier.
Once this happens, we need to shut down cwidget in order to restore
the terminal to its original state. If you skip this step, the
terminal will be garbled and will not work properly when your program
exits.
cw::toplevel::shutdown();
And that's it! To compile the program, change to the directory containing hello.cc and run:
$ g++ -o hello hello.cc $(pkg-config --cflags --libs cwidget)
Of course, you'll need to have the g++ and libcwidget-dev packages installed for this to work!
Posted Fri Jul 4 13:03:00 2008So I've been inexcusably tardy in announcing this, but Obey Arthur Liu is working on aptitude for Google's Summer of Code program. His goal is to write a third interface to the program, using GTK+ to produce the UI; as the abstract for his project states:
I will create a GTK+ GUI for Aptitude that will work alongside improved current ncurses and command-line interfaces. This will offer an alternative to Synaptic with an interface design geared toward usability and advanced functionality.
I'm looking forward to seeing what he comes up with! I think there are a lot of interesting possibilities in the design space of GUI package managers; hopefully he'll have time to explore at least a few of them. At the moment he's focusing on figuring out the care and feeding of the apt library backend and learning some of the quirks you have to deal with when writing a frontend against it.
Arthur's blog can be found at http://www.milliways.fr and on Planet Debian. The Mercurial repository for his work can currently be found at http://dev.graffit.net/aptitude/hg/.
Posted Thu Jun 19 07:22:00 2008I've released version 0.4.11.4 of the aptitude
package manager (release
notes). The
main motivation for this release is bug #483920, which would
cause the resolver to choose solutions badly (e.g., it might prefer
downgrading a bunch of packages to keeping them at their current
versions). It also includes a simple fix for bug #136874, the
fact that the output of aptitude search is badly suited for scripts
(it still is, but now there's a command-line option that will make it
better).
Regarding the OpenSSL debacle, Julien Blache writes:
Worst Debian day ever since the 2003 compromise. And that was a BAD one.
I disagree. This is far, far worse than the 2003 compromise. The compromise was scary, but the key updates for users were straightforward and as far as we know, user security was never actually compromised. In contrast, every single user who uses Debian or Ubuntu for anything serious is now (Update: and has been for two years) vulnerable to attacks on their supposedly secure cryptography [0] unless they perform a labor-intensive and error-prone series of steps to regenerate all their cryptographic keys -- not to mention finding a secure way to distribute their public keys to everyone who needs them!
[0]: Update: I should perhaps make it clear that I mean anyone who generated a key on such a system. But in a way this makes things worse: unless you're willing to regenerate every key in sight, you need to check each key manually, which means that there's a nontrivial chance that you'll overlook one and leave yourself vulnerable...
Posted Wed May 14 08:10:00 2008We've spent the last week and a half moving out of the bizarre twilight zone known as Redmond into the city of Seattle proper. This cuts down on my commute tremendously (although poor Kate has to do the opposite of what I used to do each day), and it's great to be able to walk to the grocery store whenever I want. It may also mean that I'll cut back a bit on my Debian work in favor of actually having a life.
Half my stuff is still in boxes, so I'll be busy with this move for a while longer, but at least I have Internet and email access again now.
Posted Fri May 9 22:30:00 2008I talked to my mother last week about the upcoming Pennsylvania
primary (scheduled for tomorrow, April 22nd). She lives in the
semi-rural Pennsylvania town where I grew up, and so I asked her what
her impression was of how the locals felt about the campaign.
Well,
she said, they think the war is a disaster and they
don't want to vote for McCain because they think he'll continue it
forever. And of course they don't want to vote for a black man. And
they all hate Hillary and think she's evil. So they're having some
trouble trying to decide who to vote for; they can't figure out which
candidate they despise the least.
I've released version 0.4.11.2 of the aptitude package manager
(release
notes).
This is basically a bugfix release to clean out some problems that
were introduced in the previous release (most notably a nasty
problem in safe-upgrade).
Last weekend, I released version 0.4.11.1 of the aptitude package
manager (release
notes).
This is a minor release focusing mostly on bug-fixes and on a few
features that I've been meaning to add but that didn't make it into
0.4.11. I think the most interesting addition is --show-why, which
is like --show-deps but traces back to the closest manually
installed package.
In some wide-character locales, the fix for bug #472625 in this
upload of aptitude triggers bug #473874 and bug #474065
in apt; the symptoms are an error message about
on start-up, and messages saying that line N too long
(max 1024)
when you try to update the package lists
or install new packages. I've written patches to fix these bugs in
apt, and once they're reviewed by the other apt maintainers they
should be fixed in the next upload of apt (version 0.7.12). Until
then, if you're bitten by this bug, you can work around it by
diverting method http
has died unexpectedly!/usr/share/aptitude/aptitude-defaults.$LANG and replacing
it with an empty file. For instance, for Russian (ru):
# dpkg-divert --rename --local --divert /usr/share/aptitude/aptitude-defaults.ru.real --add /usr/share/aptitude/aptitude-defaults.ru
# echo > /usr/share/aptitude/aptitude-defaults.ru
Once a fixed apt is uploaded, you can remove the diversion like this:
# rm /usr/share/aptitude/aptitude-defaults.ru
# dpkg-divert --rename --local --remove /usr/share/aptitude/aptitude-defaults.ru
Posted Sat Apr 5 08:00:00 2008


