------------------------------------------------------------------------------ ------------------------------------------------------------------------------ -- Cheddar is a GNU GPL real-time scheduling analysis tool. -- This program provides services to automatically check schedulability and -- other performance criteria of real-time architecture models. -- -- Copyright (C) 2002-2020, Frank Singhoff, Alain Plantec, Jerome Legrand, -- Hai Nam Tran, Stephane Rubini -- -- The Cheddar project was started in 2002 by -- Frank Singhoff, Lab-STICC UMR 6285, Université de Bretagne Occidentale -- -- Cheddar has been published in the "Agence de Protection des Programmes/France" in 2008. -- Since 2008, Ellidiss technologies also contributes to the development of -- Cheddar and provides industrial support. -- -- The full list of contributors and sponsors can be found in AUTHORS.txt and SPONSORS.txt -- -- This program is free software; you can redistribute it and/or modify -- it under the terms of the GNU General Public License as published by -- the Free Software Foundation; either version 2 of the License, or -- (at your option) any later version. -- -- This program 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 General Public License for more details. -- -- You should have received a copy of the GNU General Public License -- along with this program; if not, write to the Free Software -- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -- -- -- Contact : cheddar@listes.univ-brest.fr -- ------------------------------------------------------------------------------ -- Last update : -- $Rev$ -- $Date$ -- $Author: singhoff $ ------------------------------------------------------------------------------ ------------------------------------------------------------------------------ with Glib; use Glib; with Gtk.Enums; use Gtk.Enums; with Gtk.Style; use Gtk.Style; with Gdk.Drawable; use Gdk.Drawable; with Gdk.Event; use Gdk.Event; with Gdk.Window; use Gdk.Window; with Gdk.Rectangle; use Gdk.Rectangle; with Gtk.Drawing_Area; use Gtk.Drawing_Area; with Gtk.Handlers; use Gtk.Handlers; package body graphical_editor.double_buffer is package event_cb is new Gtk.Handlers.Return_Callback (widget_type => gtk_double_buffer_record, return_type => Boolean); package void_cb is new Gtk.Handlers.Callback (widget_type => gtk_double_buffer_record); function configure (buffer : access gtk_double_buffer_record'class; event : Gdk.Event.gdk_event) return Boolean; -- Callback when the buffer is resized function expose (buffer : access gtk_double_buffer_record'class; event : Gdk.Event.gdk_event) return Boolean; -- Callback when the window needs to redraw itself on the screen function create_internal_pixmap (buffer : access gtk_double_buffer_record'class) return Gdk.Pixmap.gdk_pixmap; -- Create one of the internal pixmaps used by the buffer, with the -- correct size. procedure destroy_cb (buffer : access gtk_double_buffer_record'class); -- Called when the widget is destroyed, to free up some memory ------------- -- Gtk_New -- ------------- procedure gtk_new (buffer : out gtk_double_buffer) is begin buffer := new gtk_double_buffer_record; double_buffer.initialize (buffer); end gtk_new; ---------------- -- Initialize -- ---------------- procedure initialize (buffer : access gtk_double_buffer_record'class) is begin Gtk.Drawing_Area.Initialize (buffer); -- Note: the pixmap is created in the resize routine -- and the GC is created in the Realize_Cb routine. -- Connect the signals event_cb.Connect (buffer, "configure_event", event_cb.To_Marshaller (configure'access)); event_cb.Connect (buffer, "expose_event", event_cb.To_Marshaller (expose'access)); void_cb.Connect (buffer, "destroy", void_cb.To_Marshaller (destroy_cb'access)); end initialize; ---------------------------- -- Create_Internal_Pixmap -- ---------------------------- function create_internal_pixmap (buffer : access gtk_double_buffer_record'class) return Gdk.Pixmap.gdk_pixmap is pix : Gdk.Pixmap.gdk_pixmap; begin Gdk.Pixmap.Gdk_New (pix, Get_Window (buffer), gint (Get_Allocation_Width (buffer)), gint (Get_Allocation_Height (buffer))); return pix; end create_internal_pixmap; --------------- -- Configure -- --------------- function configure (buffer : access gtk_double_buffer_record'class; event : Gdk.Event.gdk_event) return Boolean is old_pixmap : constant Gdk.Pixmap.gdk_pixmap := buffer.pixmap; old_triple : constant Gdk.Pixmap.gdk_pixmap := buffer.triple_buffer; use type Gdk.Pixmap.gdk_pixmap; begin buffer.pixmap := create_internal_pixmap (buffer); if buffer.use_triple_buffer then buffer.triple_buffer := create_internal_pixmap (buffer); end if; if old_pixmap /= null then -- If Back_Store is True, then we want to keep the content -- of the old pixmap, and thus we copy it to the new one. if buffer.back_store then declare old_width : gint; old_height : gint; begin Get_Size (gdk_window (old_pixmap), old_width, old_height); Gdk.Drawable.Draw_Rectangle (buffer.pixmap, Get_Background_GC (Get_Style (buffer), state_normal), Filled => True, X => 0, Y => 0, Width => Gdk.Event.Get_Width (event), Height => Gdk.Event.Get_Height (event)); --Gdk.Drawable.Copy_Area Gdk.Drawable.Draw_Drawable (buffer.pixmap, Get_Foreground_GC (Get_Style (buffer), state_normal), old_pixmap, 0, 0, 0, 0, Width => old_width, Height => old_height); end; end if; Gdk.Pixmap.Unref (old_pixmap); end if; if old_triple /= null then -- If Back_Store is True, then we want to keep the content -- of the old pixmap, and thus we copy it to the new one. if buffer.back_store then declare old_width : gint; old_height : gint; begin Get_Size (gdk_window (old_triple), old_width, old_height); Gdk.Drawable.Draw_Rectangle (buffer.triple_buffer, Get_Background_GC (Get_Style (buffer), state_normal), Filled => True, X => 0, Y => 0, Width => Gdk.Event.Get_Width (event), Height => Gdk.Event.Get_Height (event)); Gdk.Drawable.Draw_Drawable (buffer.triple_buffer, Get_Foreground_GC (Get_Style (buffer), state_normal), old_triple, 0, 0, 0, 0, old_width, old_height); end; end if; Gdk.Pixmap.Unref (old_triple); end if; return True; end configure; ---------------- -- Destroy_Cb -- ---------------- procedure destroy_cb (buffer : access gtk_double_buffer_record'class) is use type Gdk.Pixmap.gdk_pixmap; begin if buffer.pixmap /= null then Gdk.Pixmap.Unref (buffer.pixmap); end if; if buffer.triple_buffer /= null then Gdk.Pixmap.Unref (buffer.triple_buffer); end if; end destroy_cb; ------------ -- Expose -- ------------ function expose (buffer : access gtk_double_buffer_record'class; event : Gdk.Event.gdk_event) return Boolean is area : constant Gdk.Rectangle.gdk_rectangle := Gdk.Event.Get_Area (event); begin if buffer.use_triple_buffer then -- If the event was generated manually, we need to update -- the Triple_Buffer with the value of the double_buffer, -- unless of course the buffer is frozen. if Gdk.Event.Get_Send_Event (event) then if buffer.is_frozen then buffer.should_update_on_screen := True; else Gdk.Drawable.Draw_Drawable (buffer.triple_buffer, Get_Foreground_GC (Get_Style (buffer), state_normal), buffer.pixmap, 0, 0, 0, 0, Width => gint (Get_Allocation_Width (buffer)), Height => gint (Get_Allocation_Height (buffer))); end if; end if; -- Copy the triple buffer to the screen Gdk.Drawable.Draw_Drawable (Get_Window (buffer), Get_Foreground_GC (Get_Style (buffer), state_normal), buffer.triple_buffer, area.X, area.Y, area.X, area.Y, Width => gint (area.Width), Height => gint (area.Height)); elsif not buffer.is_frozen then -- Copy the double buffer to the screen Gdk.Drawable.Draw_Drawable (Get_Window (buffer), Get_Foreground_GC (Get_Style (buffer), state_normal), buffer.pixmap, area.X, area.Y, area.X, area.Y, Width => gint (area.Width), Height => gint (area.Height)); else buffer.should_update_on_screen := True; end if; return False; end expose; ---------------- -- Get_Pixmap -- ---------------- function get_pixmap (buffer : access gtk_double_buffer_record) return Gdk.Drawable.gdk_drawable is begin return Gdk.Drawable.gdk_drawable (buffer.pixmap); end get_pixmap; -------------------- -- Set_Back_Store -- -------------------- procedure set_back_store (buffer : access gtk_double_buffer_record; back_store : Boolean := True) is begin buffer.back_store := back_store; end set_back_store; ------------ -- Freeze -- ------------ procedure freeze (buffer : access gtk_double_buffer_record) is begin buffer.is_frozen := True; end freeze; ---------- -- Thaw -- ---------- procedure thaw (buffer : access gtk_double_buffer_record) is begin buffer.is_frozen := False; if buffer.should_update_on_screen then Draw (buffer); end if; end thaw; ----------------------- -- Set_Triple_Buffer -- ----------------------- procedure set_triple_buffer (buffer : access gtk_double_buffer_record; use_triple_buffer : Boolean := True) is use type Gdk.gdk_window; begin buffer.use_triple_buffer := use_triple_buffer; -- If we do not want triple_buffer but already have one, delete it if not use_triple_buffer and then buffer.triple_buffer /= null then Gdk.Pixmap.Unref (buffer.triple_buffer); end if; -- If we do want a triple buffer, create the pixmap if use_triple_buffer then buffer.triple_buffer := create_internal_pixmap (buffer); -- Copy the current value of the pixmap in it Gdk.Drawable.Draw_Drawable (buffer.triple_buffer, Get_Foreground_GC (Get_Style (buffer), state_normal), buffer.pixmap, 0, 0, 0, 0, Width => gint (Get_Allocation_Width (buffer)), Height => gint (Get_Allocation_Height (buffer))); end if; end set_triple_buffer; end graphical_editor.double_buffer;