--------------------------------------------------------------------------------
--                                                                            --
-- Copyright (C) 2004, RISC OS Ada Library (RASCAL) developers.               --
--                                                                            --
-- This library is free software; you can redistribute it and/or              --
-- modify it under the terms of the GNU Lesser General Public                 --
-- License as published by the Free Software Foundation; either               --
-- version 2.1 of the License, or (at your option) any later version.         --
--                                                                            --
-- This library is distributed in the hope that it will be useful,            --
-- but WITHOUT ANY WARRANTY; without even the implied warranty of             --
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU           --
-- Lesser General Public License for more details.                            --
--                                                                            --
-- You should have received a copy of the GNU Lesser General Public           --
-- License along with this library; if not, write to the Free Software        --
-- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA    --
--                                                                            --
--------------------------------------------------------------------------------

-- $Author$
-- $Date$
-- $Revision$

with Kernel;            use Kernel;
with Interfaces.C;      use Interfaces.C;

with Ada.Strings.Unbounded;
with Ada.Exceptions;    use Ada.Exceptions;

with RASCAL.Memory;     use RASCAL.Memory;
with RASCAL.HeapSort;

package body RASCAL.ToolboxWindow is

   Toolbox_ObjectMiscOp                : constant := 16#44EC6#;

   Window_ClassSWI                     : constant := 16#82880#;
   Window_PostFilter                   : constant := 16#82881#;
   Window_PreFilter                    : constant := 16#82882#;
   Window_GetPointerInfo               : constant := 16#82883#;
   Window_WimpToToolbox                : constant := 16#82884#;
   Window_RegisterExternal             : constant := 16#82885#;
   Window_DeregisterExternal           : constant := 16#82886#;
   Window_RegisterFilter               : constant := 16#82888#;
   Window_DeregisterFilter             : constant := 16#82889#;

   Window_EnumerateGadgets             : constant := 16#8288A#;
   Window_GadgetGetIconList            : constant := 16#8288B#;
   Window_ExtractGadgetInfo            : constant := 16#828BE#;
   Window_PlotGadget                   : constant := 16#828BF#;

   Window_GetWimpHandle                : constant := 16#0#;
   Window_AddGadget                    : constant := 16#1#;
   Window_RemoveGadget                 : constant := 16#2#;
   Window_SetMenu                      : constant := 16#3#;
   Window_GetMenu                      : constant := 16#4#;
   Window_SetPointer                   : constant := 16#5#;
   Window_GetPointer                   : constant := 16#6#;
   Window_SetHelpMessage               : constant := 16#7#;
   Window_GetHelpMessage               : constant := 16#8#;
   Window_AddKeyboardShortcuts         : constant := 16#9#;
   Window_RemoveKeyboardShortcuts      : constant := 16#A#;
   Window_SetTitle                     : constant := 16#B#;
   Window_GetTitle                     : constant := 16#C#;
   Window_SetDefaultFocus              : constant := 16#D#;
   Window_GetDefaultFocus              : constant := 16#E#;
   Window_SetExtent                    : constant := 16#F#;
   Window_GetExtent                    : constant := 16#10#;
   Window_ForceRedraw                  : constant := 16#11#;
   Window_SetToolBars                  : constant := 16#12#;
   Window_GetToolBars                  : constant := 16#13#;

   Service_WindowModuleStarting        : constant := 16#82881#;
   Service_WindowModuleDying           : constant := 16#82882#;
   Service_GadgetRegistered            : constant := 16#82883#;
   Service_GadgetDeregistered          : constant := 16#82884#;

   --

   procedure Get_PointerInfo(Flags : in System.Unsigned_Types.Unsigned := 0;
                             X_Pos : out Integer;
                             Y_Pos : out Integer;
                             State : out Integer;
                             Object: out Integer;
                             Gadget: out Integer) is

      Register : aliased Kernel.swi_regs;
      Error    : oserror_access;
   begin
      Register.R(0) := Int(Unsigned_to_Int(Flags));
      Error := Kernel.Swi (Window_GetPointerInfo, Register'Access, Register'Access);

      if Error /= null then
         pragma Debug(Report("ToolboxWindow.Get_Pointer_Info: " & To_Ada(Error.ErrMess)));
         OS.Raise_Error(Error);
      end if;
      X_Pos  := integer(Register.R(0));
      Y_Pos  := integer(Register.R(1));
      State  := integer(Register.R(2));
      Object := integer(Register.R(3));
      Gadget := integer(Register.R(4));
   end Get_PointerInfo;

   --

   procedure Wimp_To_Toolbox (Window    : in Wimp_Handle_Type;
                              Icon      : in Icon_Handle_Type;
                              Object    : out Object_ID;
                              Component : out Component_ID;
                              Flags     : in System.Unsigned_Types.Unsigned := 0) is

      Register : aliased Kernel.swi_regs;
      Error    : oserror_access;
   begin
      Register.R(0) := Int(Unsigned_to_Int(Flags));
      Register.R(1) := Int(Window);
      Register.R(2) := Int(Icon);
      Error := Kernel.Swi (Window_WimpToToolbox, Register'Access, Register'Access);

      if Error /= null then
         pragma Debug(Report("ToolboxWindow.Wimp_To_Toolbox: " & To_Ada(Error.ErrMess)));
         OS.Raise_Error(Error);
      end if;
      Object := Object_ID(Register.R(0));
      Component := Component_ID(Register.R(1));      
   end Wimp_To_Toolbox;

   --

   procedure Register_External(Gadget_Type : in Integer;
                               Handler_SWI : in Integer;
                               Flags       : in System.Unsigned_Types.Unsigned := 0) is

      Register : aliased Kernel.swi_regs;
      Error    : oserror_access;
   begin
      Register.R(0) := Int(Unsigned_to_Int(Flags));
      Register.R(1) := Int(Gadget_Type);
      Register.R(2) := Int(Handler_SWI);
      Error := Kernel.Swi (Window_RegisterExternal, Register'Access, Register'Access);
      if Error /= null then
         pragma Debug(Report("ToolboxWindow.Register_External: " & To_Ada(Error.ErrMess)));
         OS.Raise_Error(Error);
      end if;
   end Register_External;

   --

   procedure DeRegister_External(Gadget_Type : in Integer;
                                 Handler_SWI : in Integer;
                                 Flags       : in System.Unsigned_Types.Unsigned := 0) is

      Register : aliased Kernel.swi_regs;
      Error    : oserror_access;
   begin
      Register.R(0) := Int(Unsigned_to_Int(Flags));
      Register.R(1) := Int(Gadget_Type);
      Register.R(2) := Int(Handler_SWI);
      Error := Kernel.Swi (Window_DeRegisterExternal, Register'Access, Register'Access);
      if Error /= null then
         pragma Debug(Report("ToolboxWindow.DeRegister_External: " & To_Ada(Error.ErrMess)));
         OS.Raise_Error(Error);
      end if;
   end DeRegister_External;

   --
     
   procedure Extract_GadgetInfo (Template : in Address;
                                 Gadget   : in Component_ID;
                                 Block    : out Address;
                                 BlockSize: out Integer;
                                 Flags    : in System.Unsigned_Types.Unsigned := 0) is
   
      Register : aliased Kernel.swi_regs;
      Error    : oserror_access;
   begin
      Register.R(0) := Int(Unsigned_to_Int(Flags));
      Register.R(1) := Adr_To_Int(Template);
      Register.R(2) := int(Gadget);
      Error := Kernel.Swi (Window_ExtractGadgetInfo, Register'Access, Register'Access);

      if Error /= null then
         pragma Debug(Report("ToolboxWindow.Extract_GadgetInfo " & To_Ada(Error.ErrMess)));
         OS.Raise_Error(Error);
      end if;
      Block     := Int_To_Adr(Register.R(0));
      BlockSize := Integer (Register.R(1));      
   end Extract_GadgetInfo;

   --

   function Get_WimpHandle (Window : in Object_ID;
                            Flags  : in System.Unsigned_Types.Unsigned := 0) return Wimp_Handle_Type is

      Register : aliased Kernel.swi_regs;
      Error    : oserror_access;
   begin
      Register.R(0) := int(Unsigned_to_Int(Flags));
      Register.R(1) := int(Window);
      Register.R(2) := Window_GetWimpHandle;
      Error := Kernel.swi(Toolbox_ObjectMiscOp,Register'Access,Register'Access);

      if Error /= null then
         pragma Debug(Report("Toolbox.Get_WimpHandle: " & To_Ada(Error.ErrMess)));
         OS.Raise_Error(Error);
      end if;
      return Wimp_Handle_Type(Register.R(0));
   end Get_WimpHandle;

   --

   procedure Plot_Gadget (Gadget : in Address;
                          Flags  : in System.Unsigned_Types.Unsigned := 0) is

      Register : aliased Kernel.swi_regs;
      Error    : oserror_access;
   begin
      Register.R(0) := Int(Unsigned_to_Int(Flags));
      Register.R(1) := Adr_To_Int(Gadget);
      Error := Kernel.Swi (Window_PlotGadget, Register'Access, Register'Access);

      if Error /= null then
         pragma Debug(Report("ToolboxWindow.Plot_Gadget : " & To_Ada(Error.ErrMess)));
         OS.Raise_Error(Error);
      end if;
   end Plot_Gadget;

   --

   procedure Add_Gadget (Window : in Object_ID;
                         Gadget : in Address;
                         Flags  : in System.Unsigned_Types.Unsigned := 0) is

      Register : aliased Kernel.swi_regs;
      Error    : oserror_access;
   begin
      Register.R(0) := -1;--Int(Unsigned_to_Int(Flags));
      Register.R(1) := Int(Window);
      Register.R(2) := Window_AddGadget;
      Register.R(3) := Adr_To_Int(Gadget);
      Error := Kernel.Swi (Toolbox_ObjectMiscOp, Register'Access, Register'Access);

      if Error /= null then
         pragma Debug(Report("ToolboxWindow.Add_Gadget: " & To_Ada(Error.ErrMess)));
         OS.Raise_Error(Error);
      end if;
   end Add_Gadget;

   --

   procedure Remove_Gadget (Window    : in Object_ID;
                            Component : in Component_ID;
                            Flags     : in System.Unsigned_Types.Unsigned := 0) is

      Register : aliased Kernel.swi_regs;
      Error    : oserror_access;
   begin

      Register.R(0) := Int(Unsigned_to_Int(Flags));
      Register.R(1) := Int(Window);
      Register.R(2) := Window_RemoveGadget;
      Register.R(3) := Int(Component);
      Error := Kernel.Swi (Toolbox_ObjectMiscOp, Register'Access, Register'Access);

      if Error /= null then
         pragma Debug(Report("ToolboxWindow.Remove_Gadget: " & To_Ada(Error.ErrMess)));
         OS.Raise_Error(Error);
      end if;
   end Remove_Gadget;

   --

   procedure Set_Menu (Window  : in Object_ID;
                       Menu    : in Object_ID;
                       Flags   : in System.Unsigned_Types.Unsigned := 0) is

      Register : aliased Kernel.swi_regs;
      Error    : oserror_access;
   begin
      Register.R(0) := Int(Unsigned_to_Int(Flags));
      Register.R(1) := Int(Window);
      Register.R(2) := Window_SetMenu;
      Register.R(3) := Int(Menu);
      Error := Kernel.Swi (Toolbox_ObjectMiscOp, Register'Access, Register'Access);

      if Error /= null then
         pragma Debug(Report("ToolboxWindow.Set_Menu: " & To_Ada(Error.ErrMess)));
         OS.Raise_Error(Error);
      end if;
   end Set_Menu;

   --

   function Get_Menu (Window : in Object_ID;
                      Flags  : in System.Unsigned_Types.Unsigned := 0) return Object_ID is

      Register : aliased Kernel.swi_regs;
      Error    : oserror_access;
   begin
      Register.R(0) := Int(Unsigned_to_Int(Flags));
      Register.R(1) := Int(Window);
      Register.R(2) := Window_GetMenu;
      Error := Kernel.Swi (Toolbox_ObjectMiscOp, Register'Access, Register'Access);

      if Error /= null then
         pragma Debug(Report("ToolboxWindow.Get_Menu: " & To_Ada(Error.ErrMess)));
         OS.Raise_Error(Error);
      end if;
      return Object_ID(Register.R(0));
   end Get_Menu;

   --

   procedure Set_Pointer (Window     : in Object_ID;
                          SpriteName : in string;
                          X_Hotspot  : in integer;
                          Y_Hotspot  : in integer;
                          Flags      : in System.Unsigned_Types.Unsigned := 0) is

      Register      : aliased Kernel.swi_regs;
      Error         : oserror_access;
      SpriteName_0  : String := SpriteName & ASCII.NUL;
   begin
      Register.R(0) := Int(Unsigned_to_Int(Flags));
      Register.R(1) := Int(Window);
      Register.R(2) := Window_SetPointer;
      Register.R(3) := Adr_To_Int(SpriteName_0'Address);
      Register.R(4) := Int(X_Hotspot);
      Register.R(5) := Int(Y_Hotspot);
      Error := Kernel.Swi (Toolbox_ObjectMiscOp, Register'Access, Register'Access);

      if Error /= null then
         pragma Debug(Report("ToolboxWindow.Set_Pointer: " & To_Ada(Error.ErrMess)));
         OS.Raise_Error(Error);
      end if;
   end Set_Pointer;

   --

   procedure Get_Pointer (Window   : in Object_ID;
                         SpriteName: out UString;
                         X_Hotspot : out integer;
                         Y_Hotspot : out integer;
                         Flags     : in System.Unsigned_Types.Unsigned := 0) is

      Register    : aliased Kernel.swi_regs;
      Buffer_Size : integer := 0;
      Error       : oserror_access;
   begin
      Register.R(0) := Int(Unsigned_to_Int(Flags));
      Register.R(1) := Int(Window);
      Register.R(2) := Window_GetPointer;
      Error := Kernel.Swi (Toolbox_ObjectMiscOp, Register'Access, Register'Access);

      if Error /= null then
         pragma Debug(Report("ToolboxWindow.Get_Pointer: " & To_Ada(Error.ErrMess)));
         OS.Raise_Error(Error);
      end if;

      Buffer_Size := Integer(Register.R(4));

      declare
         Buffer : String(1..Buffer_Size);
      begin
         Register.R(0) := Int(Unsigned_to_Int(Flags));
         Register.R(1) := Int(Window);
         Register.R(2) := Window_GetPointer;
         Register.R(3) := Adr_To_Int(Buffer'Address);
         Register.R(4) := Int(Buffer_Size);
         Error := Kernel.Swi (Toolbox_ObjectMiscOp, Register'Access, Register'Access);

         if Error /= null then
            pragma Debug(Report("ToolboxWindow.Get_Pointer: " & To_Ada(Error.ErrMess)));
            OS.Raise_Error(Error);
         end if;
         X_Hotspot := Integer(Register.R(5));
         Y_Hotspot := Integer(Register.R(6));
         SpriteName:=U(MemoryToString(Buffer'Address));
      end;
   end Get_Pointer;

   --

   procedure Set_Help (Window : in Object_ID;
                       Help   : in String;
                       Flags  : in System.Unsigned_Types.Unsigned := 0) is

      Register  : aliased Kernel.swi_regs;
      Error     : oserror_access;
      Help_0    : String := Help & ASCII.NUL;
   begin
      Register.R(0) := Int(Unsigned_to_Int(Flags));
      Register.R(1) := Int(Window);
      Register.R(2) := Window_SetHelpMessage;
      Register.R(3) := Adr_To_Int(Help_0'Address);
      Error := Kernel.swi(Toolbox_ObjectMiscOp,register'Access,register'Access);

      if Error /= null then
         pragma Debug(Report("ToolboxWindow.Set_Help: " & To_Ada(Error.ErrMess)));
         OS.Raise_Error(Error);
      end if;
   end Set_Help;

   --

   function Get_Help (Window : in Object_ID;
                      Flags  : in System.Unsigned_Types.Unsigned := 0) return String is

      Register    : aliased Kernel.swi_regs;
      Buffer_Size : integer := 0;
      Error       : oserror_access;
   begin
      Register.R(0) := Int(Unsigned_to_Int(Flags));
      Register.R(1) := Int(Window);
      Register.R(2) := Window_GetHelpMessage;
      Error := Kernel.Swi (Toolbox_ObjectMiscOp, Register'Access, Register'Access);

      if Error /= null then
         pragma Debug(Report("ToolboxWindow.Get_Help: " & To_Ada(Error.ErrMess)));
         OS.Raise_Error(Error);
      end if;

      Buffer_Size := Integer(Register.R(4));

      declare
         Buffer : String(1..Buffer_Size);
      begin
         Register.R(0) := Int(Unsigned_to_Int(Flags));
         Register.R(1) := Int(Window);
         Register.R(2) := Window_GetHelpMessage;
         Register.R(3) := Adr_To_Int(Buffer'Address);
         Register.R(4) := Int(Buffer_Size);
         Error := Kernel.Swi (Toolbox_ObjectMiscOp, Register'Access, Register'Access);

         if Error /= null then
            pragma Debug(Report("ToolboxWindow.Get_Help (II): " & To_Ada(Error.ErrMess)));
            OS.Raise_Error(Error);
         end if;
         return MemoryToString(Buffer'Address);
      end;
   end Get_Help;

   --

   procedure Add_KeyboardShortcuts (Window    : in Object_ID;
                                    Shortcuts : in KeyboardShortcutList_Type;
                                    Flags     : in System.Unsigned_Types.Unsigned := 0) is

      Register  : aliased Kernel.swi_regs;
      Error     : oserror_access;
   begin
      Register.R(0) := Int(Unsigned_to_Int(Flags));
      Register.R(1) := Int(Window);
      Register.R(2) := Window_AddKeyboardShortcuts;
      Register.R(3) := Int(Shortcuts'Length);
      Register.R(4) := Adr_To_Int(Shortcuts'Address);
      Error := Kernel.swi(Toolbox_ObjectMiscOp,register'Access,register'Access);

      if Error /= null then
         pragma Debug(Report("ToolboxWindow.Add_KeyboardShortcuts: " & To_Ada(Error.ErrMess)));
         OS.Raise_Error(Error);
      end if;
   end Add_KeyboardShortcuts;

   --

   procedure Remove_KeyboardShortcuts (Window    : in Object_ID;
                                       Shortcuts : in KeyboardShortcutList_Type;
                                       Flags     : in System.Unsigned_Types.Unsigned := 0) is

      Register  : aliased Kernel.swi_regs;
      Error     : oserror_access;
   begin
      Register.R(0) := Int(Unsigned_to_Int(Flags));
      Register.R(1) := Int(Window);
      Register.R(2) := Window_RemoveKeyboardShortcuts;
      Register.R(3) := Int(Shortcuts'Length);
      Register.R(4) := Adr_To_Int(Shortcuts'Address);
      Error := Kernel.swi(Toolbox_ObjectMiscOp,register'Access,register'Access);

      if Error /= null then
         pragma Debug(Report("ToolboxWindow.Remove_KeyboardShortcuts: " & To_Ada(Error.ErrMess)));
         OS.Raise_Error(Error);
      end if;
   end Remove_KeyboardShortcuts;

   --

   procedure Set_Title (Window : in Object_ID;
                        Title  : in String;
                        Flags  : in System.Unsigned_Types.Unsigned := 0) is

      Register   : aliased Kernel.swi_regs;
      Error      : oserror_access;
      Title_0    : String := Title & ASCII.NUL;
   begin
      Register.R(0) := Int(Unsigned_to_Int(Flags));
      Register.R(1) := Int(Window);
      Register.R(2) := Window_SetTitle;
      Register.R(3) := Adr_To_Int(Title_0'Address);
      Error := Kernel.swi(Toolbox_ObjectMiscOp,register'Access,register'Access);

      if Error /= null then
         pragma Debug(Report("ToolboxWindow.Set_Title: " & To_Ada(Error.ErrMess)));
         OS.Raise_Error(Error);
      end if;
   end Set_Title;

   --

   function Get_Title (Window : in Object_ID;
                       Flags  : in System.Unsigned_Types.Unsigned := 0) return String is

      Register    : aliased Kernel.swi_regs;
      Buffer_Size : integer := 0;
      Error       : oserror_access;
   begin
      Register.R(0) := Int(Unsigned_to_Int(Flags));
      Register.R(1) := Int(Window);
      Register.R(2) := Window_GetTitle;
      Error := Kernel.Swi (Toolbox_ObjectMiscOp, Register'Access, Register'Access);

      if Error /= null then
         pragma Debug(Report("ToolboxWindow.Get_Title: " & To_Ada(Error.ErrMess)));
         OS.Raise_Error(Error);
      end if;

      Buffer_Size := Integer(Register.R(4));

      declare
         Buffer : String(1..Buffer_Size);
      begin
         Register.R(0) := Int(Unsigned_to_Int(Flags));
         Register.R(1) := Int(Window);
         Register.R(2) := Window_GetTitle;
         Register.R(3) := Adr_To_Int(Buffer'Address);
         Register.R(4) := Int(Buffer_Size);
         Error := Kernel.Swi (Toolbox_ObjectMiscOp, Register'Access, Register'Access);

         if Error /= null then
            pragma Debug(Report("ToolboxWindow.Get_Title: " & To_Ada(Error.ErrMess)));
            OS.Raise_Error(Error);
         end if;
         return MemoryToString(Buffer'Address);
      end;
   end Get_Title;

   --

   procedure Set_DefaultFocus (Window    : in Object_ID;
                               Component : in Component_ID;
                               Flags     : in System.Unsigned_Types.Unsigned := 0) is

      Register : aliased Kernel.swi_regs;
      Error    : oserror_access;
   begin
      Register.R(0) := Int(Unsigned_to_Int(Flags));
      Register.R(1) := Int(Window);
      Register.R(2) := Window_SetDefaultFocus;
      Register.R(3) := Int(Component);
      Error := Kernel.Swi (Toolbox_ObjectMiscOp, Register'Access, Register'Access);

      if Error /= null then
         pragma Debug(Report("ToolboxWindow.Set_Default_Focus: " & To_Ada(Error.ErrMess)));
         OS.Raise_Error(Error);
      end if;
   end Set_DefaultFocus;

   --

   function Get_DefaultFocus (Window : in Object_ID;
                              Flags  : in System.Unsigned_Types.Unsigned := 0) return Component_ID is

      Register : aliased Kernel.swi_regs;
      Error    : oserror_access;
   begin
      Register.R(0) := Int(Unsigned_to_Int(Flags));
      Register.R(1) := Int(Window);
      Register.R(2) := Window_GetDefaultFocus;
      Error := Kernel.Swi (Toolbox_ObjectMiscOp, Register'Access, Register'Access);

      if Error /= null then
         pragma Debug(Report("ToolboxWindow.Get_Default_Focus: " & To_Ada(Error.ErrMess)));
         OS.Raise_Error(Error);
      end if;
      return Component_ID(Register.R(0));
   end Get_DefaultFocus;

   --

   procedure Set_Extent (Window : in Object_ID;
                         BBox   : in Toolbox_BBox_Type;
                         Flags  : in System.Unsigned_Types.Unsigned := 0) is

      Register : aliased Kernel.swi_regs;
      Error    : oserror_access;
   begin
      Register.R(0) := Int(Unsigned_to_Int(Flags));
      Register.R(1) := Int(Window);
      Register.R(2) := Window_SetExtent;
      Register.R(3) := Adr_To_Int(BBox'Address);
      Error := Kernel.Swi (Toolbox_ObjectMiscOp, Register'Access, Register'Access);

      if Error /= null then
         pragma Debug(Report("ToolboxWindow.Set_Extent: " & To_Ada(Error.ErrMess)));
         OS.Raise_Error(Error);
      end if;
   end Set_Extent;

   --

   function Get_Extent (Window : in Object_ID;
                        Flags  : in System.Unsigned_Types.Unsigned := 0) return Toolbox_BBox_Type is

      Register : aliased Kernel.swi_regs;
      Error    : oserror_access;
      BBox     : Toolbox_BBox_Type;
   begin
      Register.R(0) := Int(Unsigned_to_Int(Flags));
      Register.R(1) := Int(Window);
      Register.R(2) := Window_GetExtent;
      Register.R(3) := Adr_To_Int(BBox'Address);
      Error := Kernel.Swi (Toolbox_ObjectMiscOp, Register'Access, Register'Access);

      if Error /= null then
         pragma Debug(Report("ToolboxWindow.Get_Extent: " & To_Ada(Error.ErrMess)));
         OS.Raise_Error(Error);
      end if;
      return BBox;
   end Get_Extent;

   --

   procedure Force_Redraw (Window : in Object_ID;
                           BBox   : in Toolbox_BBox_Type;
                           Flags  : in System.Unsigned_Types.Unsigned := 0) is

      Register : aliased Kernel.swi_regs;
      Error    : oserror_access;
   begin
      Register.R(0) := Int(Unsigned_to_Int(Flags));
      Register.R(1) := Int(Window);
      Register.R(2) := Window_ForceRedraw;
      Register.R(3) := Adr_To_Int(BBox'Address);
      Error := Kernel.Swi (Toolbox_ObjectMiscOp, Register'Access, Register'Access);

      if Error /= null then
         pragma Debug(Report("ToolboxWindow.Force_Redraw: " & To_Ada(Error.ErrMess)));
         OS.Raise_Error(Error);
      end if;
   end Force_Redraw;

   --
   
   procedure Set_Toolbars (Window   : in Object_ID;
                           Toolbar  : in Object_ID;
                           Bar_Type : in Toolbox_Toolbar_Type) is

      Register : aliased Kernel.swi_regs;
      Error    : oserror_access;
   begin
      Register.R(3) := 0;
      Register.R(4) := 0;
      Register.R(5) := 0;
      Register.R(6) := 0;

      case Bar_Type is
      when Internal_Bottom_Left => Register.R(0) := 1; Register.R(3) := Int(Toolbar);
      when Internal_Top_Left    => Register.R(0) := 2; Register.R(4) := Int(Toolbar);
      when External_Bottom_Left => Register.R(0) := 4; Register.R(5) := Int(Toolbar);
      when External_Top_Left    => Register.R(0) := 8; Register.R(6) := Int(Toolbar);
      end case;

      Register.R(1) := Int(Window);
      Register.R(2) := Window_SetToolBars;
      Error := Kernel.Swi (Toolbox_ObjectMiscOp, Register'Access, Register'Access);

      if Error /= null then
         pragma Debug(Report("ToolboxWindow.Set_Toolbars: " & To_Ada(Error.ErrMess)));
         OS.Raise_Error(Error);
      end if;
   end Set_Toolbars;

   --

   function Get_Toolbars (Window   : in Object_ID;
                          Bar_Type : in Toolbox_Toolbar_Type) return Object_ID is

      Register : aliased Kernel.swi_regs;
      Error    : oserror_access;
   begin
      case Bar_Type is
      when Internal_Bottom_Left => Register.R(0) := 1;
      when Internal_Top_Left    => Register.R(0) := 2;
      when External_Bottom_Left => Register.R(0) := 4;
      when External_Top_Left    => Register.R(0) := 8;
      end case;

      Register.R(1) := Int(Window);
      Register.R(2) := Window_GetToolBars;
      Error := Kernel.Swi (Toolbox_ObjectMiscOp, Register'Access, Register'Access);

      if Error /= null then
         pragma Debug(Report("ToolboxWindow.Get_Toolbars: " & To_Ada(Error.ErrMess)));
         OS.Raise_Error(Error);
      end if;

      case Bar_Type is
      when Internal_Bottom_Left => return Object_ID(Register.R(0));
      when Internal_Top_Left    => return Object_ID(Register.R(1));
      when External_Bottom_Left => return Object_ID(Register.R(2));
      when External_Top_Left    => return Object_ID(Register.R(3));
      end case;
   end Get_Toolbars;

   --

   function Enumerate_Gadgets (Window : in Object_ID;
                               Flags  : in System.Unsigned_Types.Unsigned := 0) return Gadget_List_Type is

      Register    : aliased Kernel.swi_regs;
      Buffer_Size : integer := 0;
      Byte_Size   : integer := 0;
      Error       : oserror_access;
      WimpWindow  : Wimp_Handle_Type := Get_WimpHandle(Window);
   begin
      Register.R(0) := Int(Unsigned_to_Int(Flags));
      Register.R(1) := Int(WimpWindow);
      Register.R(2) := -1;
      Register.R(3) := 0;
      Error := Kernel.Swi (Window_EnumerateGadgets, Register'Access, Register'Access);

      if Error /= null then
         pragma Debug(Report("ToolboxWindow.Enumerate_Gadget(1): " & To_Ada(Error.ErrMess)));
         OS.Raise_Error(Error);
      end if;
      Buffer_Size := integer(Register.R(4));
      Byte_Size   := Buffer_Size;
      pragma Debug(Report ("Buffersize: " & intstr(Buffer_Size)));

      if Buffer_Size = -1 then
         Raise_Exception(No_Toolbox_Window'Identity,"No_Toolbox_Window");
      end if;

      Buffer_Size := Buffer_Size / 4;
      if (Buffer_Size * 4) < integer(Register.R(4)) then
         Buffer_Size := Buffer_Size + 1;
      end if;

      declare
         Buffer : Gadget_List_Type(1..Buffer_Size);
      begin
         Register.R(0) := Int(Unsigned_to_Int(Flags));
         Register.R(1) := Int(WimpWindow);
         Register.R(2) := -1;
         Register.R(3) := Adr_To_Int(Buffer'Address);
         Register.R(4) := Int(Byte_Size*4);
         Error := Kernel.Swi (Window_EnumerateGadgets, Register'Access, Register'Access);

         if Error /= null then
            pragma Debug(Report("ToolboxWindow.Enumerate_Gadget(2): " & To_Ada(Error.ErrMess)));
            OS.Raise_Error(Error);
         end if;
         pragma Debug(Report ("Bytes written: " & intstr(integer(Register.R(4)))));

         if integer(Register.R(2)) /= 0 then
            Raise_Exception(Enumeration_Buffer_Overrun'Identity,"Enumeration_Buffer_Overrun");
         end if;
         return Buffer;
      end;
   end Enumerate_Gadgets;

   --

   function Get_UnusedGadget (Window : in Object_ID) return Component_ID is

      Gadgets : Gadget_List_Type := Enumerate_Gadgets(Window);
   begin
      if Gadgets'Last > 0 then
         RASCAL.HeapSort.Sort(Gadgets(Gadgets'First)'Address,Gadgets'Last,4);


         if Gadgets(Gadgets'Last) < 16#7fffff# then
            return Component_ID'(Gadgets(Gadgets'Last) + 1);
         else
            for i in reverse Gadgets'range loop
               if Gadgets(i) > Gadgets(i-1)+1 then
                  return Component_ID'(Gadgets(i-1)+1);
               end if;
            end loop;
         end if;
         Raise_Exception(Too_Many_Gadgets'Identity,
                         "RASCAL.ToolboxWindow.Get_UnusedGadget: Too many gadgets.");
      end if;
      return 1;
   end Get_UnusedGadget;

   --

   function Is_Open (Window : in Object_ID) return Boolean is

      WinID : Wimp_Handle_Type := Get_WimpHandle (Window);
   begin
      return WimpWindow.Is_Open (WinID);
   end Is_Open;
   
   --

   procedure Get_Position (Window : in Object_ID;
                           X_Pos  : out Integer;
                           Y_Pos  : out Integer) is

      WinID : Wimp_Handle_Type := Get_WimpHandle (Window);
   begin
      WimpWindow.Get_WindowPosition(WinID,X_Pos,Y_Pos);
   end Get_Position;

   --
   
end RASCAL.ToolboxWindow;
