File: double_buffer.adb

package info (click to toggle)
libgtkada 2.24.4dfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: jessie, jessie-kfreebsd
  • size: 12,208 kB
  • ctags: 1,676
  • sloc: ada: 119,686; ansic: 4,719; sh: 3,003; makefile: 690; xml: 338; perl: 70
file content (368 lines) | stat: -rw-r--r-- 12,536 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
-----------------------------------------------------------------------
--          GtkAda - Ada95 binding for the Gimp Toolkit              --
--                                                                   --
--                     Copyright (C) 1998-1999                       --
--        Emmanuel Briot, Joel Brobecker and Arnaud Charlet          --
--                                                                   --
-- This library 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 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 --
-- General Public License for more details.                          --
--                                                                   --
-- You should have received a copy of the GNU 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.                                       --
--                                                                   --
-----------------------------------------------------------------------

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;
pragma Elaborate_All (Gtk.Handlers);

package body 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 : Gdk.Pixmap.Gdk_Pixmap := Buffer.Pixmap;
      Old_Triple : 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.Draw_Drawable
                 (Buffer.Pixmap,
                  Get_Foreground_GC (Get_Style (Buffer), State_Normal),
                  Src      => Old_Pixmap,
                  Xsrc     => 0,
                  Ysrc     => 0,
                  Xdest    => 0,
                  Ydest    => 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),
                  Src      => Old_Triple,
                  Xdest    => 0,
                  Ydest    => 0,
                  Xsrc     => 0,
                  Ysrc     => 0,
                  Width    => Old_Width,
                  Height   => 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 : 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),
                  Src      => Buffer.Pixmap,
                  Xdest    => 0,
                  Ydest    => 0,
                  Xsrc     => 0,
                  Ysrc     => 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),
            Src      => Buffer.Triple_Buffer,
            Xdest    => Area.X,
            Ydest    => Area.Y,
            Xsrc     => Area.X,
            Ysrc     => 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),
            Src      => Buffer.Pixmap,
            Xdest    => Area.X,
            Ydest    => Area.Y,
            Xsrc     => Area.X,
            Ysrc     => 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),
            Src      => Buffer.Pixmap,
            Xdest    => 0,
            Ydest    => 0,
            Xsrc     => 0,
            Ysrc     => 0,
            Width    => Gint (Get_Allocation_Width (Buffer)),
            Height   => Gint (Get_Allocation_Height (Buffer)));
      end if;
   end Set_Triple_Buffer;

end Double_Buffer;