Thursday, November 20, 2014

3 days using Android Lollipop on Nexus 5

Have heard all the good things about Andriod Lollipop, and eagerly waiting for the released. When the factory image was out, I was going to install the image on my Nexus 5 myself, but latter found that the platform tools of the SDK has only 32-bit binaries, although I had downloaded a 64-bit version of the SDK. It seems this is a known problem and ignored by Google, saying install a 32-bit compatible layer should do the trick. I don't want to install megabytes of 32-bit layer on top of my pure 64-bit installation system!

Well, I waited not long after, the OTA came and I quickly installed the upgrade (Nov 18). The new GUI does not really impress me, but so long as it does it job, I am fine with it. But compare with the older one from KitKat, I like the KitKat one more.

The new clock application use current time to change its background color, that annoying me greatly, and it has no option to turn that off! It may look nice on the presentation, but it give no value to me. I like to look at the clock on a black background! The layout of the international clock changes to a list from the 2 column layout in KitKat. I think the 2 column layout give me a better presentation.

Browser tabs, I could not find the handle of tabs in the browser, I did not recall I had allowed the browser to merged tabs with apps. Well, at least this time I have a setting to turn "Merge tabs and apps" to off.

The battery saver mode is fine. But why should it insist to change the status and home buttons bar to orange background? With the battery saver icon on the status bar, it is already obvious, why on earth change those background color? I know what I am doing, and does not need such thing to remind me I am in battery saver mode. And no option to turn the color change off.

For media video playing, the volume control button no longer work as expected, instead, I have to click on the button, then tap on the speaker symbol to get sound changes, and dragging on the sound meter bar no longer work. This is really bad engineering.

Skype could not login any more after upgrade to Lollipop, even upgrade to the latest version. One commenter said it needs to be removed and re-install, I follow suite, it could log in again and skype test call works ok, I haven't try the video call yet, will see.

Lollipop defaults to use white background, it hurt my eyes. The color theme of KitKat looks more comfortable to the eyes.

Except those complains, so far so good, the battery usage maybe improve a little, but hard to tell for I am a light user, will see for a longer period of usage.

Wednesday, November 19, 2014

Simple EC CA script for use with OpenSSL

For some testing purposes, I need to create some elliptic-curve certificates. There is no script from OpenSSL that could create the certificate directly. So I modified the supplied CA.sh to create a ecCA.sh.

The usage is almost the same as CA.sh, plus some EC specific commands.
ecCa.sh -h
usage: ecCA.sh [-curve name] -list-curves|-newcert|-newreq|-newreq-nodes|-newca|-sign|-pkcs12|-verify

Use -list-curves to list out all the supported curves. The default CA curve is secp521r1 and default certificate curve is prime256v1.

Here are some simple step to create a EC CA and a signed EC certificate.
  1. Run command "ecCA.sh -newca", which will then ask you a serious of questions to create your CA certificate. You could use the default but do remember to enter a common name for the cert, otherwise you won't be able to create one. You will have a demoCA subdirectory created under the current directory.
  2. Run "ecCA.sh -newreq", and answer the questions, you will have a new key and certificate request with name "newkey.pem" and "newreq.pem".
  3. Run "ecCA.sh -sign", and follow the instruction, you will have a signed certificate "newcert.pem".
  4. Run "ecCA.sh -pkcs12", will create a PKCS12 formated file "newcert.p12", which could be used to import the certificate into browser.
You could download the ecCA.sh script here.

Tuesday, November 18, 2014

Google Chrome and IPv6 literate address

I don't have an established IPv6 network, only a small LAN with 3 machines for occasional IPv6 testing. So only literate address is using, for my laziness, I gave the machines the addresses of 10:10::1/96,10:10::10/96 and 10:10::20/96 accordingly.

When I try to access the web server at URL http://[10:10:20], the address works fine with Firefox, but Chrome give me DNS error.  Why a literate address need DNS resolving?  Searching around, and found a very old bug report issue 39830, it seems Chrome could not recognise my IPv6 network and startup without IPv6 support at all.

After adding the flag "--enable-ipv6" to the command line, it works again. Chrome is too "smart" to work correctly on my network.

Thursday, November 6, 2014

Run fcgiwrap with nginx under Slackware

I need to do some test on perl CGI scripts, but with NGINX server, it is not supported directly to run those CGI scripts.  Search around, there is this fcgiwrap tool.  It looks exactly like what I need for the simple test.

Fcgiwrap depends on fcgi library, which has a SlackBuild script.  I install the fcgi library with sbopkg, and proceed to write a SlackBuild script for fcgiwrap.  The fcgiwrap is a very simple program, it has only one C file for the main program.  But it needs a spawning parent to control it, the author provide a simple perl script (on the main page of the fcgirwap project.) to spawn the fcgiwrap program.  I also borrow the startup script from Nginx's FastCGI example and modified a little and name it rc.spawn-fcgi.  Both the scripts are included in the SlackBuild package that I have submitted.

After installing it, I add the following section into the server section of nginx.conf file:
  location ~ \.pl$ {
     root /var/www/cgi;
     try_files $uri =404;
            include        fastcgi_params;
     fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
     fastcgi_pass unix:/tmp/cgi.sock;
   }
After started the spawn-fcgi and reload nginx's config, the perl CGI works without problem.

Tuesday, November 4, 2014

OpenVMS got a new life

Well, it is an old news actually, but still new to me. I was not reading the OpenVMS news group for awhile. When one day I have some free time, I read it, and found this interesting news:

On July 31, 2014, HP and VMS Software, Inc. (VSI) announced, VSI has entered into a license agreement with HP to develop and release future versions of OpenVMS and most OpenVMS layered products (OpenVMS eco-system).

I have a hobby license (VAX/OpenVMS) and run a small installation through SIMH simulator, but I have not boot it up for quite a while, I hope I could still remember the administrator's password ^_^. My interest of this OS comes from my university days, when all students use the VAX/OpenVMS system for email or some school assignments. I thought it is so much better than the DOS used in the PC, but unfortunately there is no PC version. But then DEC was bought by Compact then by HP, but it is not treated well over these new owners and HP put its future to doom until this announcement. I think HP make a big mistake for not doing any meaningful development on it and bet its future on the dying Itanium chip.

VSI seems re-united a few folks from the original DEC team and hope it will bring a much bright future for the 37 years old OS. It seems, there will be an x86 port of the OS. Not sure when it will be finished? Would it be available for the hobby program? We'll see what come out from VSI.

Thursday, April 10, 2014

Internationalized application with Gtkada.Intl

Gtkada comes with Gtkada.Intl, which is a binding for libintl to provide support for string internationalization.

In this example, a very simple program is developed to illustrate the usage of Gtkada.Intl package.

We use the helloworld example, and modified it to support i18n. You could find all the source at GitHub.

The directory structure is similar as before, and we are using Makefile to automate some tasks.


|- Makefile.common
|- intl
|  |- obj/
|  |- src/
|  |- po/
|  |   |- Makefile
|  |   `- build_skeleton.pl
|  |- Makefile
|  `- generate_locale_path.sh
...
src/intl.adb:
...
with Gtkada.Intl;     use Gtkada.Intl;

with intl_cb; use intl_cb;
with intl_locale;

procedure Intl is
   Win    : Gtk_Window;
   Button : Gtk_Button;
   prgname : constant String := "intl";
begin
   -- procedure calls to setup Locale and text domain binding
   SetLocale;
   Text_Domain (prgname);
   Bind_Text_Domain (prgname, intl_locale.path);

...
   Win.Set_Title (-"Window");
...
   Gtk_New (Button, -"Hello World");
...
end Intl;
Here, we call SetLocale, Text_Domain and Bind_Text_Domain to initialize the locale data. The Bind_Text_Domain procedure needs a locale path as its second parameter, as the path may change on different system, we need a way to tell the program where is the location. A script generate_locale_path.sh was created. It is called from the Makefile, when ever there is changed in the locale path, it will generate a new src/intl_locale.ads file. A sample file is as follow:
-- This is an automatically generated file during compilation
-- Please don't edit it by hand.
-- Generated at 2014-04-09 23:45

package Intl_Locale is
   path : constant String := "/usr/local/share/locale";
end Intl_Locale;
Each string that is to be translated has a "-" signed in front. Messages in src/intl_cb.adb are also altered. We won't list the detail source here.

To generate the pot file, a modified version of build_skeleton.pl borrowed from the GtkAda project is used. There are a few modifications that make build_skeleton.pl works much better than the original one:

  • Use the perl Text::Balanced module to capture quoted string, which will work for a case like -("Hello world (from Ada)!");. The original script will get a partial string "Hello world (from Ada".
  • Use the perl Tie::IxHash module to preserve the order of message strings appear in the source file, which give translation a better view of the content near by.
  • Allow spaces in between '-', '(' and '"', for the case like -   (   "Hello world 2!");, it will not be captured by the original script.
  • Allow replace of Ada.Characters.Latin_1.LF to \n besides ASCII.LF
  • Add translation of quoted '"' in the string to \" in -("Ada said ""Hello World!");, which will allow gettext to work correctly.
  • Use command parameters for project specific information, so that it could be used on other projects without modifications.
  • Change the POT-Creation-Date format to include time and timezone information.
  • Only check src/ and its sub directories.

A Makefile is borrowed from the GtkAda project and simplified.

po/Makefile
LANGS:=zh_CN
CP:=cp
prgname := intl
## Refresh all translations by extracting the strings from the current sources
refresh:
 ./build_skeleton.pl > ${prgname}.pot
 ${foreach lang,${LANGS}, \
 if [ -f ${lang}.po ]; then true; else ${CP} ${prgname}.pot ${lang}.po; fi; \
 msgmerge --no-wrap --update ${lang}.po ${prgname}.pot}

## Install the translation files
$(LANGS): 
 -msgfmt -o $@.gmo $@.po --statistics --check-header --check-format --check-domain

clean:
 -$(RM) *.gmo
A simple run of it under the po directory will give us a simple pot file (intl.pot):
# Translation file for intl example app
# Copyright (C) 2014 Zhu Qun-Ying
#
msgid ""
msgstr ""
"Project-Id-Version: intl\n"
"Report-Msgid-Bugs-To: zhu.qunying@gmail.com\n"
"POT-Creation-Date: 2014-04-10 22:29-0700\n"
"PO-Revision-Date: \n"
"Last-Translator: \n"
"Language-Team: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"

#: intl_cb.adb
msgid "button clicked"
msgstr ""

#: intl_cb.adb
msgid "button_quit is called"
msgstr ""

#: intl_cb.adb
msgid "Delete event encounter."
msgstr ""

#: intl.adb
msgid "Hello World"
msgstr ""

#: intl.adb
msgid "Window"
msgstr ""

We have defined a default translation language zh_CN in the Makefile, so after the make command, we also have zh_CN.po file for translation. If there is no existing zh_CN.po, it will be a copy of the intl.pot file. If there exist a zh_CN.po file and has translation, it will be merged with the intl.pot file if any changes have been made.

In order to better edit it, an editor that knows the format of the po file will ease your translation work. I am using vim with po.vim plugin.

Under po directory, run make zh_CN will compile the zh_CN.po file to zh_CN.gmo.

At the intl directory, we could issue the command:

make prefix=/usr
Which will generated the src/intl_locale.ads file and set the locale path to "/usr/share/locale" and compile the program.

Just for test, we copy the po/zh_CN.gmo to /usr/share/locale/zh_CN/LC_MESSAGES/intl.mo, then run the command:

LANG=zh_CN.utf8 obj/intl
The simple window with a button 世界你好 is shown. Click on the button, the program will exit, and you will get some output from command line:
按钮被点击
调用 button_quit

For advance usage of gettext utilities, please refer to the GNU gettext utilities document.

All the source is available at GitHub

Friday, April 4, 2014

A useful small tool - BASH History Suggest Box

One day, I was reading the updates from freecode.com. I noticed this small utility BASH History Suggest Box, it looks interesting from its screenshot:

I decided to give it a try. It is very useful, it reminds me the history window of 4DOS command line interpreter at the old DOS days.

I thought this tool is quite useful for some people, so I submitted the build scripts for my favorite Linux distribution Slackware to SlackBuilds.org. The build script is not yet shown up on the official SlackBuilds.org, you could not search it yet. It is just updated (2014-04-13), and you could now search from SlackBuilds.org or use sbopkg. You could still download the build script here.

P.S. There maybe segmentation fault on some system for the official 1.2.1 release, a patched from upstream git tree is included in the build script (sigseg.patch), if you are building for other system, you may need to apply the patch first before build.

P.P.S Updated to 1.3, and remove the unnecessary patch in the script. Should be in Willy's tree soon. Note the package name has changed from "hstr" to "hh".

Wednesday, March 26, 2014

Getting Started with GtkAda - Drawing

Many widgets, like buttons, do all their drawing themselves. You just tell them the label you want to see, and they figure out what font to use, draw the button outline and focus rectangle, etc. Sometimes, it is necessary to do some custom drawing. In that case, a Gtk_Drawing_Area might be the right widget to use. It offers a canvas on which you can draw by connecting to the "draw" signal.

The contents of a widget often need to be partially or fully redrawn, e.g. when another window is moved and uncovers part of the widget, or when tie window containing it is resized. It is also possible to explicitly cause part or all of the widget to be redrawn, by calling Gtk.Widget.Queue_Draw() or its variants. GtkAda takes care of most of the details by providing a ready-to-use cairo context to the ::draw signal handler.

The following example shows a ::draw signal handler. It is a bit more complicated than the previous examples, since it also demonstrates input event handling by means of ::button-press and ::motion-notify handlers.

src/draw.adb
with Gtk.Window;       use Gtk.Window;
with Gtk.Frame;        use Gtk.Frame;
with Gtk.Button;       use Gtk.Button;
with Gtk.Drawing_Area; use Gtk.Drawing_Area;
with Gtkada.Handlers;  use Gtkada.Handlers;
with Gdk.Event;        use Gdk.Event;
with draw_cb; use draw_cb;

with Gtk.Main;
with Gtk.Enums;

procedure Draw is
   Win   : Gtk_Window;
   Frame : Gtk_Frame;
   Da    : Gtk_Drawing_Area;
begin
   --  Initialize GtkAda.
   Gtk.Main.Init;

   -- create a top level window
   Gtk_New (Win);
   Win.Set_Title ("Drawing Area");
   -- set the border width of the window
   Win.Set_Border_Width (8);
   -- connect the "destroy" signal
   Win.On_Destroy (main_quit'Access);

   -- create a frame
   Gtk_New (Frame);
   Frame.Set_Shadow_Type (Gtk.Enums.Shadow_In);
   Win.Add (Frame);

   Gtk_New (Da);
   -- set a minimum size
   Da.Set_Size_Request (100, 100);
   Frame.Add (Da);

   -- Signals used to handle the backing surface
   Da.On_Draw (draw_cb.draw_cb'Access);
   Da.On_Configure_Event (configure_event_cb'Access);
   -- Event signals
   Da.On_Motion_Notify_Event (motion_notify_event_cb'Access);
   Da.On_Button_Press_Event (button_press_event_cb'Access);

   -- Ask to receive events the drawing area doesn't normally
   -- subscribe to. In particular, we need to ask for the
   -- button press and motion notify events that want to handle.
   Da.Set_Events (Da.Get_Events or Button_Press_Mask or Pointer_Motion_Mask);

   -- Now that we are done packing our widgets, we show them all
   -- in one go, by calling Win.Show_All.
   -- This call recursively calls Show on all widgets
   -- that are contained in the window, directly or indirectly.
   Win.Show_All;

   -- All GTK applications must have a Gtk.Main.Main. Control ends here
   -- and waits for an event to occur (like a key press or a mouse event),
   -- until Gtk.Main.Main_Quit is called.
   Gtk.Main.Main;
end Draw;
src/draw_cb.ads:
with Gtk.Widget;  use Gtk.Widget;
with Gtk.Button;  use Gtk.Button;
with Glib.Object;

with Gdk.Event;
with Cairo;

package draw_cb is
   procedure main_quit (Self : access Gtk_Widget_Record'Class);

   function draw_cb
     (Self : access Gtk_Widget_Record'Class;
      Cr   : Cairo.Cairo_Context)
      return Boolean;

   -- Create a new surface of the appropriate size to store our scribbles
   function configure_event_cb
     (Self  : access Gtk_Widget_Record'Class;
      Event : Gdk.Event.Gdk_Event_Configure)
      return  Boolean;

   -- Handle motion events by continuing to draw if button 1 is
   -- still held down. The ::motion-notify signal handler receives
   -- a GdkEventMotion struct which contains this information.
   function motion_notify_event_cb
     (Self  : access Gtk_Widget_Record'Class;
      Event : Gdk.Event.Gdk_Event_Motion)
      return  Boolean;

   -- Handle button press events by either drawing a rectangle
   -- or clearing the surface, depending on which button was pressed.
   -- The ::button-press signal handler receives a GdkEventButton
   -- struct which contains this information.
   function button_press_event_cb
     (Self  : access Gtk_Widget_Record'Class;
      Event : Gdk.Event.Gdk_Event_Button)
      return  Boolean;
end draw_cb;
src/draw_cb.adb:
with Glib;       use Glib;

with Gdk.Types;  use Gdk.Types;
with Gdk.Window;
with Gtk.Main;

package body draw_cb is

   -- Button defintions from gtk-3.0/gdk/gdkevents.h
   -- The primary button. This is typically the left button, or the
   -- right button in a left-handed setup.
   Gdk_Button_Primary : constant := 1;
   --  The secondary button. This is typically the right mouse button, or the
   -- left button in a left-handed setup.
   Gdk_Button_Secondary : constant := 3;

   surface : Cairo.Cairo_Surface;
   use type Cairo.Cairo_Surface;

   procedure main_quit (Self : access Gtk_Widget_Record'Class) is
   begin
      if surface /= Cairo.Null_Surface then
         Cairo.Surface_Destroy (surface);
      end if;

      Gtk.Main.Main_Quit;
   end main_quit;

   procedure Clear_Surface is
      Cr : Cairo.Cairo_Context;
   begin
      Cr := Cairo.Create (surface);
      Cairo.Set_Source_Rgb (Cr, 1.0, 1.0, 1.0);
      Cairo.Paint (Cr);
      Cairo.Destroy (Cr);
   end Clear_Surface;

   -- Redraw the screen from the surface. Note that the ::draw
   -- signal receives a ready-to-be-used cairo_t that is already
   -- clipped to only draw the exposed areas of the widget
   function draw_cb
     (Self : access Gtk_Widget_Record'Class;
      Cr   : Cairo.Cairo_Context)
      return Boolean
   is
   begin
      Cairo.Set_Source_Surface (Cr, surface, 0.0, 0.0);
      Cairo.Paint (Cr);
      return False;
   end draw_cb;

   function configure_event_cb
     (Self  : access Gtk_Widget_Record'Class;
      Event : Gdk.Event.Gdk_Event_Configure)
      return  Boolean
   is
   begin
      if surface /= Cairo.Null_Surface then
         Cairo.Surface_Destroy (surface);
      end if;
      surface :=
         Gdk.Window.Create_Similar_Surface
           (Self.Get_Window,
            Cairo.Cairo_Content_Color,
            Self.Get_Allocated_Width,
            Self.Get_Allocated_Height);
      -- Initialize the surface to white
      Clear_Surface;

      -- We've handled the configure event, no need for further processing.
      return True;
   end configure_event_cb;

   -- Draw a rectangle on the surface at the given position
   procedure draw_brush
     (Self : access Gtk_Widget_Record'Class;
      x    : Gdouble;
      y    : Gdouble)
   is
      Cr : Cairo.Cairo_Context;
   begin

      -- Paint to the surface, where we store our state
      Cr := Cairo.Create (surface);
      Cairo.Rectangle (Cr, x - 3.0, y - 3.0, 6.0, 6.0);
      Cairo.Fill (Cr);
      Cairo.Destroy (Cr);

      -- Now invalidate the affected region of the drawing area.
      Self.Queue_Draw_Area (Gint (x - 3.0), Gint (y - 3.0), 6, 6);
   end draw_brush;

   function motion_notify_event_cb
     (Self  : access Gtk_Widget_Record'Class;
      Event : Gdk.Event.Gdk_Event_Motion)
      return  Boolean
   is
   begin
      -- paranoia check, in case we haven't gotten a configure event
      if surface = Cairo.Null_Surface then
         return False;
      end if;

      if (Event.State and Gdk.Types.Button1_Mask) > 0 then
         draw_brush (Self, Event.X, Event.Y);
      end if;

      -- We've handled it, stop processing
      return True;
   end motion_notify_event_cb;

   function button_press_event_cb
     (Self  : access Gtk_Widget_Record'Class;
      Event : Gdk.Event.Gdk_Event_Button)
      return  Boolean
   is
   begin
      -- paranoia check, in case we haven't gotten a configure event
      if surface = Cairo.Null_Surface then
         return False;
      end if;

      if Event.Button = Gdk_Button_Primary then
         draw_brush (Self, Event.X, Event.Y);
      elsif Event.Button = Gdk_Button_Secondary then
         Clear_Surface;
         Self.Queue_Draw;
      end if;
      -- We've handled the event, stop processing
      return True;
   end button_press_event_cb;
end draw_cb;
draw.gpr:
with "gtkada";

project Draw is

   for Source_Dirs use ("src");
   for Object_Dir use "obj";
   for Main use ("draw.adb");

   --  Enable Ada 2005.
   package Compiler is
      for Default_Switches ("ada") use ("-gnat05");
   end Compiler;

end Draw;
To compile:
gprbuild -P draw

This program is more complicated and it shows a problem with the current GtkAda (3.8.3) binding.

There is no button definition for GDK_BUTTON_PRIMARY and GDK_BUTTON_SECONDARY, etc., which have to be defined in package draw_cb ourselves by taking the definition from the gtk-3.0/gdk/gdkevents.h. As of 2013-03-26, the SVN source tree has been updated after I reported the bug, it now contains the button definitions in gdk-event.ads as Button_Primary, Button_Secondary and Button_MIddle, if you are using the SVN source after the day, you may want to use that definition directly.

The cairo surface variable is defined in the draw_cb package body, it has the similar effect of the C static definition that only procedures and functions in the package body could see it.

We use use type Cairo.Cairo_Surface; in the draw_cb package body, so that /= and = could be used directly on the type without exposing other Cairo definitions.

Saturday, March 22, 2014

Getting started with GtkAda - Building user interfaces

When constructing a more complicated user interface, with dozens or hundreds of widgets, doing all the setup work in Ada code is cumbersome, and making changes becomes next to impossible.

Thankfully, GtkAda supports the separation of user interface layout from your business logic, by using UI descriptions in an XML format that can be parsed by the Gtk_Builder class.

This example is exactly like the grid example, but using the Gtk_Builder class.

src/builder.adb:
with Gtk.Builder; use Gtk.Builder;
with Gtk.Window; use Gtk.Window;
with Gtk.Button; use Gtk.Button;
with Gtkada.Handlers;  use Gtkada.Handlers;

with builder_cb; use builder_cb;
with Glib; use Glib;
with Glib.Error; use Glib.Error;
with Gtk.Main;

procedure Builder is
   Win   : Gtk_Window;
   Button : Gtk_Button;
   builder : Gtk_Builder;
   ret : GUint;
   error : aliased GError;
begin
   --  Initialize GtkAda.
   Gtk.Main.Init;

   -- construct a Gtk_Builder instance and load our UI description
   Gtk_New (Builder);
   ret := Builder.Add_From_File ("builder.ui", error'Access);

   -- connect signal handlers to the constructed widgets
   Win := Gtk_Window (Builder.Get_Object ("window"));
   -- connect the "destroy" signal
   Win.On_Destroy (main_quit'Access);

   button := Gtk_Button (Builder.Get_Object ("button1"));
   button.On_Clicked (button_clicked'Access);

   button := Gtk_Button (Builder.Get_Object ("button2"));
   button.On_Clicked (button_clicked'Access);

   button := Gtk_Button (Builder.Get_Object ("quit"));
   -- connect the "clicked" signal of the button to destroy function
   Widget_Callback.Object_Connect
     (Button,
      "clicked",
      Widget_Callback.To_Marshaller (button_quit'Access),
      Win);
   -- All GTK applications must have a Gtk.Main.Main. Control ends here
   -- and waits for an event to occur (like a key press or a mouse event),
   -- until Gtk.Main.Main_Quit is called.
   Gtk.Main.Main;
end Builder;
src/builder_cb.ads:
with Gtk.Widget;  use Gtk.Widget;
with Gtk.Button; use Gtk.Button;

package builder_cb is
   procedure main_quit (Self : access Gtk_Widget_Record'Class);

   procedure button_clicked (Self : access Gtk_Button_Record'Class);
   procedure button_quit (Self : access Gtk_Widget_Record'Class);
end builder_cb;
src/builder_cb.adb:
with Ada.Text_IO; use Ada.Text_IO;
with Gtk.Main;

package body builder_cb is

   procedure main_quit (Self : access Gtk_Widget_Record'Class) is
   begin
      Gtk.Main.Main_Quit;
   end main_quit;

   procedure button_clicked (Self : access Gtk_Button_Record'Class) is
   begin
      Put_Line ("Hello World!");
   end button_clicked;

   procedure button_quit (Self : access Gtk_Widget_Record'Class) is
   begin
      Put_Line ("buttion_quit is called");
      Destroy (Self);
   end button_quit;
end builder_cb;
builder.gpr:
with "gtkada";

project Builder is

   for Source_Dirs use ("src");
   for Object_Dir use "obj";
   for Main use ("builder.adb");

   -- Enable Ada 2005.
   package Compiler is
     for Default_Switches ("ada") use ("-gnat05");
   end Compiler;
end Builder
builder.ui:
<interface> 
  <object id="window" class="GtkWindow"> 
    <property name="visible">True</property> 
    <property name="title">Grid</property> 
    <property name="border-width">10</property> 
    <child> 
      <object id="grid" class="GtkGrid"> 
        <property name="visible">True</property> 
        <child> 
          <object id="button1" class="GtkButton"> 
            <property name="visible">True</property> 
            <property name="label">Button 1</property> 
          </object> 
          <packing> 
            <property name="left-attach">0</property> 
            <property name="top-attach">0</property> 
          </packing> 
        </child> 
        <child> 
          <object id="button2" class="GtkButton"> 
            <property name="visible">True</property> 
            <property name="label">Button 2</property> 
          </object> 
          <packing> 
            <property name="left-attach">1</property> 
            <property name="top-attach">0</property> 
          </packing> 
        </child> 
        <child> 
          <object id="quit" class="GtkButton"> 
            <property name="visible">True</property> 
            <property name="label">Quit</property> 
          </object> 
          <packing> 
            <property name="left-attach">0</property> 
            <property name="top-attach">1</property> 
            <property name="width">2</property> 
          </packing> 
        </child> 
      </object> 
      <packing> 
      </packing> 
    </child> 
  </object> 
</interface>
To compile:
gprbuild -P builder

Note that Gtk_Builder can also be used to construct objects that are not widgets, such as tree models, adjustments, etc. That is the reason the method we use here is called Get_Object and returns a Glib.Object.GObject instead of a Gtk_Widget. That is why we need to cast the return value of Get_Object to the corresponding type to pass the compilation.

Normally, you would pass a full path to Add_From_File to make the execution of your program independent of the current directory. A common location to install UI descriptions and similar data is /usr/share/appname.

It is also possible to embed the UI description in the source code as a string and use Add_From_String to load it. But keeping the UI description in a separate file has several advantages: It is then possible to make minor adjustments to the UI without recompiling your program, and, more importantly, graphical UI editors such as glade can load the file and allow you to create and modify your UI by point-and-click.

There is one thing in this example differ from the C version. In the C example, gtk_builder_add_from_file() is called with a NULL pointer for the error parameter, in GtkAda version, the Error is a must, otherwise, you will get constraint error:

raised CONSTRAINT_ERROR : gtk-builder.adb:151 access check failed

Friday, March 21, 2014

Getting Started with GtkAda - Packing

When creating an application, you'll want to put more than one widget inside a window. Our first helloworld example only used one widget so we could simply use Add call to "pack" the widget into the window. But when you want to put more than one widget into a window, it it becomes important to control how each widget is positioned and sized. This is where packing comes in.

GtkAda comes with a large variety of layout containers whose purpose it is to control the layout of the child widgets that are added to them. You could see the Gtk+ Layout Containers for an overview. GtkAda has all the containers and normally has the form of Gtk_<Container_Name>

The following example shows how the Gtk_Grid container lets you arrange several buttons. It follows the same directory structure in the helloworld example.

src/grid.adb:
with Gtk.Main;
with Gtk.Window;      use Gtk.Window;
with Gtk.Grid;        use Gtk.Grid;
with Gtk.Button;      use Gtk.Button;
with Gtkada.Handlers; use Gtkada.Handlers;

with grid_cb; use grid_cb;

procedure Grid is
   Win    : Gtk_Window;
   Grid   : Gtk_Grid;
   Button : Gtk_Button;
begin
   --  Initialize GtkAda.
   Gtk.Main.Init;

   -- create a top level window
   Gtk_New (Win);
   Win.Set_Title ("Grid");
   -- set the border width of the window
   Win.Set_Border_Width (10);
   -- connect the "destroy" signal
   Win.On_Destroy (main_quit'Access);

   -- Here we construct the container that is going pack our buttons
   Gtk_New (Grid);

   -- Packed the container in the Window
   Win.Add (Grid);

   -- create a button with label
   Gtk_New (Button, "Button 1");
   -- connect the click signal
   Button.On_Clicked (button_clicked'Access);

   -- Place the first button in the grid cell (0, 0), and make it fill
   -- just 1 cell horizontally and vertically (ie no spanning)
   Grid.Attach (Button, 0, 0, 1, 1);

   -- create another button with label
   Gtk_New (Button, "Button 2");
   Button.On_Clicked (button_clicked'Access);

   -- Place the second button in the grid cell (1, 0), and make it fill
   -- just 1 cell horizontally and vertically (ie no spanning)
   Grid.Attach (Button, 1, 0, 1, 1);

   -- create the quit button
   Gtk_New (Button, "Quit");
   -- connect the "clicked" signal of the button to destroy function
   Widget_Callback.Object_Connect
     (Button,
      "clicked",
      Widget_Callback.To_Marshaller (button_quit'Access),
      Win);
   -- Place the Quit button in the grid cell (0, 1), and make it
   -- span 2 columns.
   Grid.Attach (Button, 0, 1, 2, 1);

   -- Now that we are done packing our widgets, we show them all
   -- in one go, by calling Win.Show_All.
   -- This call recursively calls Show on all widgets
   -- that are contained in the window, directly or indirectly.
   Win.Show_All;

   -- All GTK applications must have a Gtk.Main.Main. Control ends here
   -- and waits for an event to occur (like a key press or a mouse event),
   -- until Gtk.Main.Main_Quit is called.
   Gtk.Main.Main;
end Grid;
src/grid_cb.ads:
with Gtk.Widget;  use Gtk.Widget;
with Gtk.Button;  use Gtk.Button;
with Glib.Object;

with Gdk.Event;

package grid_cb is
   function main_del
     (Self  : access Gtk_Widget_Record'Class;
      Event : Gdk.Event.Gdk_Event)
      return  Boolean;
   procedure main_quit (Self : access Gtk_Widget_Record'Class);
   procedure button_clicked (Self : access Gtk_Button_Record'Class);
   procedure button_quit (Self : access Gtk_Widget_Record'Class);
end grid_cb;
src/grid_cb.adb:
with Ada.Text_IO; use Ada.Text_IO;

with Gtk.Main;

package body grid_cb is
   -- If you return false in the "delete_event" signal handler,
   -- GTK will emit the "destroy" signal. Returning true means
   -- you don't want the window to be destroyed.
   --
   -- This is useful for popping up 'are you sure you want to quit?'
   -- type dialogs.
   function main_del
     (Self  : access Gtk_Widget_Record'Class;
      Event : Gdk.Event.Gdk_Event)
      return  Boolean
   is
   begin
      Put_Line ("Delete event encounter.");
      return True;
   end main_del;

   procedure main_quit (Self : access Gtk_Widget_Record'Class) is
   begin
      Gtk.Main.Main_Quit;
   end main_quit;

   procedure button_clicked (Self : access Gtk_Button_Record'Class) is
   begin
      Put_Line ("Hello clicked");
   end button_clicked;

   procedure button_quit (Self : access Gtk_Widget_Record'Class) is
   begin
      Put_Line ("buttion_quit is called");
      Destroy (Self);
   end button_quit;

end grid_cb;
grid.gpr
with "gtkada";

project Grid is

   for Source_Dirs use ("src");
   for Object_Dir use "obj";
   for Main use ("grid.adb");

   --  Enable Ada 2005.
   package Compiler is
      for Default_Switches ("ada") use ("-gnat05");
   end Compiler;

end Grid
To compile the program:
gprbuild -P grid

You may notice the callback functions are exactly the same as helloworld, you could reuse it by just rename the packages or simple using the same hello_cb package and in grid.adb with and use it with hello_cb; use hello_cb;, then you don't need to change anything on the call backs.

Thursday, March 20, 2014

Getting Started with GtkAda

There is not much resources on how to program with GtkAda. GtkAda User’s Guide provides some information but not enough to start from scratch. I tried to follow the Getting Started with GTK+ but writing it with GtkAda.

I will assume you have gnat gpl 2013 and GtkAda installed. I use the svn version of GtkAda (3.8.3) in stead of the GtkAda 2013 GPL 3.4.2.

Basics

We'll start with the simplest program possible. This program will create an empty window.
The source files are under the following directory structure:
example-top-dir
  |-- obj
  |-- src
  `-- hello.gpr
src/hello.adb:
with Gtk.Main;
with Gtk.Window;      use Gtk.Window;

with Main_quit;

procedure Hello is
   Win   : Gtk_Window;
begin
   --  Initialize GtkAda.
   Gtk.Main.Init;

   -- create a top level window
   Gtk_New (Win);
   Win.Set_Title ("Window");

   -- connect the "destroy" signal
   Win.On_Destroy (main_quit'Access);

   --  Show the window
   Win.Show_All;

   --  Start the Gtk+ main loop
   Gtk.Main.Main;
end Hello
src/main_quit.adb:
with Gtk.Widget;      use Gtk.Widget;
with Gtk.Main;

procedure main_quit (Self : access Gtk_Widget_Record'Class) is
begin
   Gtk.Main.Main_Quit;
end main_quit;
The project file hello.gpr:
with "gtkada";

project Hello is

   for Source_Dirs use ("src");
   for Object_Dir use "obj";
   for Main use ("hello.adb");

   --  Enable Ada 2005.
   package Compiler is
      for Default_Switches ("ada") use ("-gnat05");
   end Compiler;

end Hello;
You then could compile the program as
gprbuild -P hello

All GtkAda application will, of course, with the Gtk.Main and Gtk.Window packages. We'll need to add a call back to quit the program, so with the Main_quit procedure.

In the main procedure Hello, we declared a Win variable as of type Gtk_Window. Since we have use Gtk.Window, we does not need to give the full path as Gtk.Window.Gtk_Window.

The following line will call Gtk.Main.Init, which is the initialization function for GtkAda; it calls the underline gtk_init() function and will setup GtkAda, the type system, the the connection to the windowing environment, etc. The Gtk.Main.Init take care of passing command line arguments counter and string array to the C gtk_init() function; this allows GTK+ to parse specific command line arguments that control the behavior of GTK+ itself. The parsed arguments will be removed from the array, leaving the unrecognized ones for your application to parse.

For more information on which command line arguments GtkAda recognizes, please refer to the Running GTK+ Applications section.

A call to Gtk_New (Win) will create a new Gtk_Window and store it inside the Win variable. Gtk_New has Gtk.Enums.WindowToplevel as its default The_Type argument, so we don't need to specify it with the call. Which means the the Gtk_Window will be managed by the windowing system: it will have a frame, a title bar and window controls, depending on the platform.

In order to terminate the application when the Win is destroyed we connect the "destroy" signal to the Main_quit function by calling Win.On_Destroy (main_quit'Access);

This function will terminate the GtkAda main loop started by calling Gtk.Main.Main later. The "destroy" signal is emitted when a widget is destroyed, either by explicitly calling Gtk.Widget.Destroy or when the widget is unparented. Top-level Gtk_Windows are also destroyed when the Close window control button is clicked.

Gtk_Window are hidden by default. By calling Win.Show_All, we are asking GtkAda to set the visibility attribute so that it can be displayed. Al this work is done after the main loop has been started.

The last line of interest is the call to Gtk.Main.Main. This function will start the GtkAda main loop and will block the control flow of Hello until Gtk.Main.Main_Quit is called.

While the program is running, GtkAda is receiving events. These are typically input events caused by the user interacting with your program, but also things like messages from the window manager or other applications. GtkAda processes these and as a result, signals may by emitted on your widgets. Connecting handlers for these signals is how you normally make your program do somthing in response to user input.

In the main_quit procedure, Gtk.Main.Main_Quit is called to quit the program.

The following example is slightly more complex, and tries to showcase some of the capabilities of GtkAda.

In the long tradition of programming languages and libraries, it is called Hello, World.

Using the same project file of the first example, here are the sources:

src/hello.adb:
with Gtk.Main;
with Gtk.Window;      use Gtk.Window;
with Gtk.Button;      use Gtk.Button;
with Gtkada.Handlers; use Gtkada.Handlers;

with hello_cb; use hello_cb;

procedure Hello is
   Win    : Gtk_Window;
   Button : Gtk_Button;
begin
   --  Initialize GtkAda.
   Gtk.Main.Init;

   -- create a top level window
   Gtk_New (Win);
   Win.Set_Title ("Window");

   -- When the window emits the "delete-event" signal (which is emitted
   -- by GTK+ in response to an event coming from the window manager,
   -- usually as a result of clicking the "close" window control), we
   -- ask it to call the on_delete_event() function as defined above.
   Win.On_Delete_Event (main_del'Access);

   -- connect the "destroy" signal
   Win.On_Destroy (main_quit'Access);

   -- set the border width of the window
   Win.Set_Border_Width (10);

   -- create a button with label
   Gtk_New (Button, "Hello World");

   -- connect the click signal
   Button.On_Clicked (button_clicked'Access);

   -- connect the "clicked" signal of the button to destroy function,
   -- it will destroy the Win when button is clicked.
   Widget_Callback.Object_Connect
     (Button,
      "clicked",
      Widget_Callback.To_Marshaller (button_quit'Access),
      Win);

   -- This packs the button into the window. A Gtk_Window inherits from Gtk_Bin
   -- which is a special container that can only have one child.
   Win.Add (Button);

   --  Show all the window
   Win.Show_All;

   -- All GTK applications must have a Gtk.Main.Main. Control ends here
   -- and waits for an event to occur (like a key press or a mouse event),
   -- until Gtk.Main.Main_Quit is called.
   Gtk.Main.Main;
end Hello;
src/hello_cb.ads:
with Gtk.Widget;  use Gtk.Widget;
with Gtk.Button;  use Gtk.Button;
with Glib.Object;

with Gdk.Event;

package hello_cb is
   function main_del
     (Self  : access Gtk_Widget_Record'Class;
      Event : Gdk.Event.Gdk_Event)
      return  Boolean;
   procedure main_quit (Self : access Gtk_Widget_Record'Class);
   procedure button_clicked (Self : access Gtk_Button_Record'Class);
   procedure button_quit (Self : access Gtk_Widget_Record'Class);
end hello_cb;
src/hello_cb.adb:
with Ada.Text_IO; use Ada.Text_IO;
with Gtk.Main;

package body hello_cb is
   -- If you return false in the "delete_event" signal handler,
   -- GTK will emit the "destroy" signal. Returning true means
   -- you don't want the window to be destroyed.
   --
   -- This is useful for popping up 'are you sure you want to quit?'
   -- type dialogs.
   function main_del
     (Self  : access Gtk_Widget_Record'Class;
      Event : Gdk.Event.Gdk_Event)
      return  Boolean
   is
   begin
      Put_Line ("Delete event encounter.");
      return True;
   end main_del;

   procedure main_quit (Self : access Gtk_Widget_Record'Class) is
   begin
      Gtk.Main.Main_Quit;
   end main_quit;

   procedure button_clicked (Self : access Gtk_Button_Record'Class) is
   begin
      Put_Line ("Hello clicked");
   end button_clicked;

   procedure button_quit (Self : access Gtk_Widget_Record'Class) is
   begin
      Put_Line ("buttion_quit is called");
      Destroy (Self);
   end button_quit;

end hello_cb;
You compile the program with the same command:
gprbuild -P hello

This time, we defined a hello_cb package to host all the call back functions.

In GtkAda, there is no need for g_signal_connect_swapped(), we use the Widget_Callback.Object_Connect method.

P.S. All source code from these series of Getting Started with GtkAda are now at GitHub.

Google wearables

If this Google Watch could function independently as a phone without a pairing smart phone, I will immediately get one when its out. If it needs a pairing smart phone then forget it!

Friday, February 21, 2014

A Slackware banner logo for rEFInd Boot Manager

The default rEFInd boot manager's logo causing the boot screen to have a white background, as rEFInd use the color of banner image's the top left corner pixel as its background color. I would like to have a black one, so I try to create a boot logo for it with a black background.
I would like to have a Slackware logo display on the boot screen, look at the the logos from "Slackware Banners, Logos, Propaganda" page, I like this one

But it is a little small and scaling it up does not look nice, I tried to vectorized it with Potrace but the result does not look good. Searching around for the font use in the image, and found out it is computer modern typewriter text. There is this project Computer Modern Unicode fonts that has the computer modern font converted from Khuth's famous TeX fonts. Now I need to use a vector drawing program, I know inkscape could do it, and proceed to install it and all its dependencies with the help of sbopkg. The installation went well.
Here is the result:

The svg source could be downloaded here.

There is a SlackBuild script for rEFInd now. The logo's png and svg source are included in the build script.

Enjoy ^_^

Monday, February 17, 2014

Install Slackware64 14.1 on a MacBook Pro 5.2

The MacBook feels its ages after upgrading to OS X Mavericks‎, it is slow and I really don't have a usage of the OS X itself. So I start my journey to install my favorite Slackware to it.

There are a few helpful sites that describe the installation of Linux on a MacBook:

Disk Partition

There are some problems that I encounter that is quite unique to this machine. I shrank the OS X partition and created a new 40G FAT partition and boot up the newly burned Slackware64 14.1 DVD. It could not boot using EFI mode, and fallback to the legacy BIOS boot mode.

After boot up, I partition the disk using cgdisk, remove the FAT partition and recreate one for Linux. An interesting thing shows up, after selected my target / partition and the ESP, it ask me whether to include an MSDOS partition to be mounted, with the same device number of my main Linux partition. I ignored it, and proceed to install the "A" and "AP" part only. Then when come to install Lilo, it stucks forever without progress. Google around, does not show any direct related problem. Then I found some mentioning of gpartsync tool, it seems in rEFInd (which I chose as my boot manager), there is one included name "gptsync_x64.efi", turn it on from the config and reboot, it does not work for me. Then I reboot into Linux with the DVD and use fdisk, Och, there is a FAT partition there. To play safe, I repartition the disk again in OS X and redo the installation with both GPT and MBR table matched, it seems fine, except it prompt me with 2 identical Linux partitions for my root mount point, I chose one and ignored the other and proceed. Lilo still complaining about config problem about append command, then I remove the append line use standard text mode only. It finally installed. There must be something wrong for what I have done for the partition, but I don't want to experiment and re-install again.

Booting Up

Since the stock kernel has EFI stub build in, I copy the huge kernel to the EFI/slackware64 and create a refind_linux.conf manually

"Boot with defaults"         "root=/dev/sda4 ro"
I hope rEFInd could pick it up and boot me into Linux directly from EFI. I restart the box, the rEFInd boot manager has the Linux choice show up, boot it, kernel complains about conflicting frame buffer driver between EFI VGA and nouveau and stops. I think it should be able to resolve it with the extra parameter "video=efifb"

I reboot and boot the Linux with BIOS mode and Lilo bring up the system. But I only have one CPU show up, it seems this is a known problem. I install the the rest packages from D, X, XAP, N, L, KDE, TCL, XFCE, Y, etc. Then download the 3.10.20 kernel source and config it to use nouveau driver only for frame buffer. It boots up fine and now I have the two CPU cores available.

There is a long delay (around 30 to 40 seconds) before rEFInd show its menu. This seems a known problem on certain MacBook. I tried the clearing the NVRAM entries method first, but it did not work for me. Then I tried using the fallback filename method, rename EFI/refind to EFI/BOOT and rename refind_x64.efi to bootx64.efi. It seems work, I now got around 6 seconds of delay. Not sure if that is normal, but at least its bearable.

Nouveau and X.org

X does not work, it said DRM is not working. I download the latest binary driver from nvidia, and it seems working fine, except after exit from X.org, I got an black screen and has to blind type commands to shutdown the machine. At system boot, I use efifb for the frame buffer driver. It seems it is a common problem, fellow slackers have the same problem "Cannot access TTYs after installing nvidia drivers on macbook pro".

The touch pad respond badly, almost like not working, google around, it seems the default setting of synaptics does not work well, I ended up with this settings under /usr/share/X11/xorg.conf.d/50-synaptics.conf

Section "InputClass"
 Identifier "touchpad"
 Driver "synaptics"
 MatchDevicePath "/dev/input/event*"
 MatchIsTouchpad "on"
 Option "FingerLow" "10"
 Option "FingerHigh" "20"
 Option "TapButton1" "1"
 Option "TapButton2" "2"
 Option "MinSpeed" "0.65"
 Option "MaxSpeed" "0.85"
 Option "TapButton3" "3"
 Option "VertTwoFingerScroll" "true"
EndSection
MinSpeed of 1 is still too fast when accessing some small links, 0.65 seems reasonable for me.

To handle the hotkeys, I used pommed-light, after a few tweak, I got it compile and running, the sound volume control works. Others are still testing.

Annoying things of the system

The iSight built-in web-cam does not work. At first, the system does not recognize the device at all, listing the usb device as some kind of development board. Even booting back to OS X does not recognize the webcam anymore. Using solution in {CODIUM();}, I manage to get the iSight webcam recognized correctly again under OS X and under Linux, lsusb recognize the device as iSight, but no luck getting it working. I don't really making use of it, so it is not a very big problem for me.

The bootup sound before the boot manger is really annoying, looking around the web, seems there are lots of people complaining. I follow the advice from MacTrast, and tried the 3 methods: overwrite the nvram settings, install a control application to mute the bootup sound, and mute the sound device before power off. Mute the sound before poweroff/reboot does not work too well and it seems does not work from Linux. Set the nvram value to 0 or 80 does not work either. The StartNinja apps seems to work first, but then I drained my battery completely and lost the setting, and I thought it did not work until I try the 2nd time, consider working.