Emacs 22.2 for Nokia N900

 

Note: if you did not end up here from my N900 main page, then you might be interested to know that I have also written an updated version of this page for Emacs 23.1.93.

This page describes the port of Emacs 22.2 for Nokia N900. This is based on a previous work for the Nokia N810.

If you simply want to grab all the material to build emacs 22.2 for the N900, here are the few simple steps required to do that:

arno@small:~$ wget -q http://ftp.gnu.org/pub/gnu/emacs/emacs-22.2.tar.gz
arno@small:~$ wget -q http://ftp.gnu.org/pub/gnu/emacs/emacs-22.2.tar.gz.sig
arno@small:~$ gpg --verify emacs-22.2.tar.gz.sig
gpg: Signature made Wed 26 Mar 2008 03:12:35 PM CET using DSA key ID BC40251C
gpg: Good signature from "Chong Yidong <cyd@stupidchicken.com>"
arno@small:~$ tar xzf emacs-22.2.tar.gz
arno@small:~$ cd emacs-22.2
arno@small:~/emacs-22.2$ hg clone http://hg.natisbad.org/N900/emacs-22.2-debian-folder/ debian
requesting all changes
adding changesets
adding manifests
adding file changes
added 1 changesets with 17 changes to 17 files
updating to branch default
17 files updated, 0 files merged, 0 files removed, 0 files unresolved

Note that you need to be in your scratchbox environment if you want to go further and compile the package. You also need to satisfy all the build dependencies of the package.

The rest of this page provides additional information on the content of the debian folder to build emacs 22.2 for the N900. There are already various pages (here and here) on Maemo wiki providing information on how applications can be packaged and built for the N900. For that reason, I only document here things worth mentioning on the files of the debian folder:

arno@small:~/emacs-22.2/$ ls -l debian
total 52
-rw-r--r-- 1 arno arno  132 2009-11-28 17:29 changelog
-rw-r--r-- 1 arno arno    2 2009-11-28 17:29 compat
-rw-r--r-- 1 arno arno 5142 2009-12-12 18:51 control
-rw-r--r-- 1 arno arno 1391 2009-11-28 17:29 copyright
drwxr-xr-x 3 arno arno 4096 2009-12-12 17:33 data
drwxr-xr-x 2 arno arno 4096 2009-11-28 17:29 patches
-rwxr-xr-x 1 arno arno   62 2009-12-12 17:49 postinst
-rwxr-xr-x 1 arno arno  389 2009-12-12 18:10 preinst
-rwxr-xr-x 1 arno arno 3319 2009-12-12 18:05 rules

Note that if you install the package, you might be interested by the additional notes on the purpose of the patch found in patches folder to allow passing emacs in fullscreen mode and the specific page on the keyboard remapping.

 


control file

The content of the control file is the following:

arno@small:~/emacs-22.2/debian$ cat control
Source: emacs
Section: user/utilities
Priority: optional
Maintainer: Arnaud Ebalard <arno@natisbad.org>
Build-Depends: debhelper (>= 5), autotools-dev, quilt
Standards-Version: 3.7.2

Package: emacs
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}
Description: The GNU Emacs editor
 GNU Emacs is the extensible self-documenting text editor. This
 package is intended for use on Nokia N900.
XB-Maemo-Icon-26:
 iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAACXBIWXMAAAsSAAAL

 ...

 bf4Xw9L60MbC16UAAAAASUVORK5CYII=

There is almost nothing specific in it if you are already familiar with usual Debian control file, except the XB-Maemo-Icon-26 entry. It contains the application icon file encoded in base64. The Application Manager displays this icon next to the package name (when installing or removing the application). The icon file should be in a format understood by the N900 (PNG is fine) and should have a size of 48x48.

Encoding the PNG icon file in base64 and concatenating it to the control file after the XB-Maemo-Icon-26: entry cant be done in the following way:

arno@small:~/emacs22.2/debian$ openssl base64 -in emacs-48x48.png | sed -e 's/^/ /' >> control

The sed part is for adding a leading space to each line of the base64-encoded icon in the control file.

 


data folder

arno@small:~/emacs-22.2/debian/$ ls -l data
-rw-r--r-- 1 arno arno  268 2009-12-12 17:33 emacs.desktop
drwxr-xr-x 1 arno arno 4096 2009-11-28 17:29 icons

emacs.desktop file

arno@small:~/emacs-22.2/$ cat data/emacs.desktop
[Desktop Entry]
Encoding=UTF-8
Version=1.0
Type=Application
Name=Emacs 22.2
Comment=The GNU Emacs editor
Exec=/usr/bin/emacs
Icon=emacs
X-Window-Icon=emacs
X-Window-Icon-Dimmed=emacs
X-HildonDesk-ShowInToolBar=true
X-Osso-Type=application/x-executable
Terminal=false

icons folder

arno@small:~/emacs-22.2/debian$ find data/icons/
data/icons/
data/icons/hicolor
data/icons/hicolor/40x40
data/icons/hicolor/40x40/apps
data/icons/hicolor/40x40/apps/emacs.png
data/icons/hicolor/48x48
data/icons/hicolor/48x48/apps
data/icons/hicolor/48x48/apps/emacs.png
data/icons/hicolor/64x64
data/icons/hicolor/64x64/apps
data/icons/hicolor/64x64/apps/emacs.png
data/icons/hicolor/scalable
data/icons/hicolor/scalable/hildon
data/icons/hicolor/scalable/hildon/emacs.png
data/icons/hicolor/128x128
data/icons/hicolor/128x128/apps
data/icons/hicolor/128x128/apps/emacs.png
data/icons/hicolor/26x26
data/icons/hicolor/26x26/apps
data/icons/hicolor/26x26/apps/emacs.png
data/icons/scalable
data/icons/scalable/apps
data/icons/scalable/apps/emacs.png

 


preinst file

The N900 root filesystem is very limited in size (200Mo) and emacs has a lot of files to be installed under /usr/share/emacs (more precisely /usr/share/emacs/emacs-22.2).

For such packages, /home/opt/ can be used to store such files. In our specific case, I wrote a simple preinst script which creates /home/opt/emacs/ folder and then a link to it from /usr/share/emacs/.

arno@small:~/emacs/debian$ cat preinst
#! /bin/sh

# Emacs is fat. Because there is limited space available
# directly in /usr/share/ for "emacs" directory, we just
# create the folder in /home/opt/ on the 1.8GB partition
# and then use a symbolic link from /usr/share/emacs

if [ ! -d /usr/share/emacs ]; then
    if [ ! -d /home/opt/emacs ]; then
	mkdir -p /home/opt/emacs
    fi
    ln -s /home/opt/emacs /usr/share/emacs
fi

 


postinst file

includes icons and an emacs.desktop file which are installed by the rule file

The package deploys icons in /usr/share/icons/hicolor folder (those are copied from data folder by rules file). In order for the system to learn about those file, the gtk-update-icon-cache needs to be called after the package has been installed. This is the purpose of the postinst script:

arno@small:~/emacs/debian$ cat postinst
#! /bin/sh

gtk-update-icon-cache -f /usr/share/icons/hicolor

 


rules files

The rules files for building the package is pretty common. It is based on the one used in the upstream Debian package, with some changes:

arno@small:~/emacs/debian$ cat rules
#!/usr/bin/make -f

include /usr/share/quilt/quilt.make

# These are used for cross-compiling and for saving the configure script
# from having to guess our platform (since we know it already)
DEB_HOST_GNU_TYPE   ?= $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE)
DEB_BUILD_GNU_TYPE  ?= $(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE)

CFLAGS = -Wall -g

ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS)))
	CFLAGS += -O0
else
	CFLAGS += -O2
endif

config.status: configure
	dh_testdir
	# Add here commands to configure the package.
	./configure --host=$(DEB_HOST_GNU_TYPE)   \
                    --build=$(DEB_BUILD_GNU_TYPE) \
                    --prefix=/usr --mandir=\$${prefix}/share/man \
                    --infodir=\$${prefix}/share/info \
                    --with-gtk --with-toolkit-scroll-bars \
                    CFLAGS="$(CFLAGS)" LDFLAGS="-Wl,-z,defs"

build: build-stamp

build-stamp: $(QUILT_STAMPFN) config.status
	dh_testdir
	$(MAKE)
	touch $@

clean:	unpatch
	dh_testdir
	dh_testroot
	rm -f build-stamp 
	-$(MAKE) distclean
ifneq "$(wildcard /usr/share/misc/config.sub)" ""
	cp -f /usr/share/misc/config.sub config.sub
endif
ifneq "$(wildcard /usr/share/misc/config.guess)" ""
	cp -f /usr/share/misc/config.guess config.guess
endif
	dh_clean 

install: build
	dh_testdir
	dh_testroot
	dh_clean -k 
	dh_installdirs

	$(MAKE) prefix=$(CURDIR)/debian/emacs/usr install

	# To save some Mo, we remove .el.gz files. We do it after they
	# have been installed to avoid patching various emacs Makefile
	# files.
	find $(CURDIR)/debian/emacs/usr -name '*.el.gz' -exec rm '{}' \;

	mkdir -p $(CURDIR)/debian/emacs/usr/share/applications/hildon/
	cp $(CURDIR)/debian/data/emacs.desktop \
	   $(CURDIR)/debian/emacs/usr/share/applications/hildon/emacs.desktop

	# Install icons
	cp -R $(CURDIR)/debian/data/icons \
	      $(CURDIR)/debian/emacs/usr/share/

binary-indep: build install
# We have nothing to do by default.

# Build architecture-dependent files here.
binary-arch: build install
	dh_testdir
	dh_testroot
	dh_link
	dh_strip
	dh_compress
	dh_fixperms
	dh_installdeb
	dh_shlibdeps
	dh_gencontrol
	dh_md5sums
	dh_builddeb

binary: binary-indep binary-arch
.PHONY: build clean binary-indep binary-arch binary install 

 


patches folder

As discussed above, in order to support switching to fullscreen mode, I have written a small patch which is stored in patches folder under the debian folder and applied automatically during the build of the package.

arno@small:~/emacs-22.2/debian/$ cat patches/handle_fullscreen_using_gtk_window_fullscreen.patch
Index: emacs-22.2/src/xterm.c
===================================================================
--- emacs-22.2.orig/src/xterm.c	2008-06-01 20:10:26.000000000 +0200
+++ emacs-22.2/src/xterm.c	2008-06-01 20:11:39.000000000 +0200
@@ -8426,87 +8426,34 @@
   return rc;
 }
 
-/* Do fullscreen as specified in extended window manager hints */
+/* Some custom hack for N900. With the following in the .emacs
+   we get fullscreen done
 
+(defun fullscreen ()
+  (interactive)
+  (set-frame-parameter nil 'fullscreen
+                       (if (frame-parameter nil 'fullscreen) nil 'fullboth)))
+(global-set-key [f6] 'fullscreen)
+
+ */
 static int
 do_ewmh_fullscreen (f)
      struct frame *f;
 {
-  int have_net_atom = wm_supports (f, "_NET_WM_STATE");
-
-  /* Some window managers don't say they support _NET_WM_STATE, but they do say
-     they support _NET_WM_STATE_FULLSCREEN.  Try that also.  */
-  if (!have_net_atom)
-      have_net_atom = wm_supports (f, "_NET_WM_STATE_FULLSCREEN");
-
-  if (have_net_atom)
-    {
-      Lisp_Object frame;
-      const char *atom = "_NET_WM_STATE";
-      const char *fs = "_NET_WM_STATE_FULLSCREEN";
-      const char *fw = "_NET_WM_STATE_MAXIMIZED_HORZ";
-      const char *fh = "_NET_WM_STATE_MAXIMIZED_VERT";
-      const char *what = NULL;
-
-      XSETFRAME (frame, f);
-
-      /* If there are _NET_ atoms we assume we have extended window manager
-         hints.  */
-      switch (f->want_fullscreen)
-        {
-        case FULLSCREEN_BOTH:
-          what = fs;
-          break;
-        case FULLSCREEN_WIDTH:
-          what = fw;
-          break;
-        case FULLSCREEN_HEIGHT:
-          what = fh;
-          break;
-        }
-
-      if (what != NULL && !wm_supports (f, what)) return 0;
+	GtkWidget *wtop = FRAME_GTK_OUTER_WIDGET(f);
 
+	if (f->want_fullscreen == FULLSCREEN_BOTH ||
+	    f->want_fullscreen == FULLSCREEN_WIDTH ||
+	    f->want_fullscreen == FULLSCREEN_HEIGHT) {
+		gtk_window_fullscreen(GTK_WINDOW(wtop));
+		f->want_fullscreen = FULLSCREEN_NONE;
+	} else
+		gtk_window_unfullscreen(GTK_WINDOW(wtop));
 
-      Fx_send_client_event (frame, make_number (0), frame,
-                            make_unibyte_string (atom, strlen (atom)),
-                            make_number (32),
-                            Fcons (make_number (0), /* Remove */
-                                   Fcons
-                                   (make_unibyte_string (fs,
-                                                         strlen (fs)),
-                                    Qnil)));
-      Fx_send_client_event (frame, make_number (0), frame,
-                            make_unibyte_string (atom, strlen (atom)),
-                            make_number (32),
-                            Fcons (make_number (0), /* Remove */
-                                   Fcons
-                                   (make_unibyte_string (fh,
-                                                         strlen (fh)),
-                                    Qnil)));
-      Fx_send_client_event (frame, make_number (0), frame,
-                            make_unibyte_string (atom, strlen (atom)),
-                            make_number (32),
-                            Fcons (make_number (0), /* Remove */
-                                   Fcons
-                                   (make_unibyte_string (fw,
-                                                         strlen (fw)),
-                                    Qnil)));
-      f->want_fullscreen = FULLSCREEN_NONE;
-      if (what != NULL)
-        Fx_send_client_event (frame, make_number (0), frame,
-                              make_unibyte_string (atom, strlen (atom)),
-                              make_number (32),
-                              Fcons (make_number (1), /* Add */
-                                     Fcons
-                                     (make_unibyte_string (what,
-                                                           strlen (what)),
-                                      Qnil)));
-    }
-
-  return have_net_atom;
+	return 1;
 }
 
+
 static void
 XTfullscreen_hook (f)
      FRAME_PTR f;

 


emacs fullscreen toggling

There is a nice page on EmacsWiki discussing how to play with fullscreen mode in Emacs. This is basically achieved by adding something like the following in your .emacs

(defun fullscreen (&optional f)
  (interactive)
  (set-frame-parameter f 'fullscreen
                       (if (frame-parameter f 'fullscreen) nil 'fullboth)))

(global-set-key [f6] 'fullscreen)

(add-hook 'after-make-frame-functions 'fullscreen)

You may wonder what the point is because there is no F6 key on the N900 keyboard. Well, we can simply correct that and spawn a F6 key on our N900 keyboard.