PLplot  5.10.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
gcw-lib.c
Go to the documentation of this file.
1 // gcw-lib - Library routines for the Gnome Canvas Widget device driver.
2 //
3 // Copyright (C) 2005 Thomas J. Duck
4 // All rights reserved.
5 //
6 //
7 // NOTICE
8 //
9 // This library is free software; you can redistribute it and/or
10 // modify it under the terms of the GNU Lesser General Public
11 // License as published by the Free Software Foundation; either
12 // version 2.1 of the License, or (at your option) any later version.
13 //
14 // This library is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 // Lesser General Public License for more details.
18 //
19 // You should have received a copy of the GNU Lesser General Public
20 // License along with this library; if not, write to the Free Software
21 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
22 // USA
23 //
24 // DESCRIPTION
25 //
26 // The gcw-lib API allows users to interact with the GCW driver. The
27 // library routines are also invoked by the driver itself when needed.
28 //
29 //
30 
31 #include "gcw.h"
32 
33 extern PLStream *pls[];
34 
35 void gcw_debug( char* msg )
36 {
37  fputs( msg, stderr );
38  fflush( stderr );
39 }
40 
41 
42 //--------------------------------------------------------------------------
43 // gcw_set_gdk_color()
44 //
45 // Sets the gdk foreground color for drawing in the current device
46 // according to the current drawing color.
47 //
48 //--------------------------------------------------------------------------
49 
51 {
52 #ifdef DEBUG_GCW_1
53  gcw_debug( "<gcw_set_gdk_color>\n" );
54 #endif
55 
56  GcwPLdev * dev = plsc->dev;
57  GdkColor color;
58 
59  color.red = (guint16) ( plsc->curcolor.r / 255. * 65535 );
60  color.green = (guint16) ( plsc->curcolor.g / 255. * 65535 );
61  color.blue = (guint16) ( plsc->curcolor.b / 255. * 65535 );
62 
63  if ( !gdk_colormap_alloc_color( dev->colormap, &color, FALSE, TRUE ) )
64  plwarn( "GCW driver <set_gdk_color>: Could not allocate color." );
65 
66  gdk_gc_set_foreground( dev->gc, &color );
67 
68 #ifdef DEBUG_GCW_1
69  gcw_debug( "</gcw_set_gdk_color>\n" );
70 #endif
71 }
72 
73 
74 //--------------------------------------------------------------------------
75 // gcw_clear_background()
76 //
77 // Clears the background pixmap for the current gcw device with the
78 // background color.
79 //
80 //--------------------------------------------------------------------------
81 
83 {
84  GcwPLdev* dev = plsc->dev;
85 
86  PLINT width, height;
87 
88 #ifdef DEBUG_GCW_1
89  gcw_debug( "<clear_background>\n" );
90 #endif
91 
92  // Retrieve the device width and height
93  width = *(PLINT *) g_object_get_data( G_OBJECT( dev->canvas ), "canvas-width" );
94  height = *(PLINT *) g_object_get_data( G_OBJECT( dev->canvas ), "canvas-height" );
95 
96  // Allocate the background color
97  gdk_colormap_alloc_color( dev->colormap, &( dev->bgcolor ), FALSE, TRUE );
98 
99  // Clear the background pixmap with the background color. Note that
100  // we are going to reset the current gdk drawing color below, so we
101  // can reuse the gc.
102  gdk_gc_set_foreground( dev->gc, &( dev->bgcolor ) );
103  gdk_draw_rectangle( dev->background, dev->gc, TRUE, 0, 0, width, height );
104 
105  // Note that our pixmap is currently clear
106  dev->pixmap_has_data = FALSE;
107 
108  // Reset the current gdk drawing color
110 
111 #ifdef DEBUG_GCW_1
112  gcw_debug( "</clear_background>\n" );
113 #endif
114 }
115 
116 
117 //--------------------------------------------------------------------------
118 // gcw_init_canvas()
119 //
120 // Initializes a canvas for use with this driver, and installs it into
121 // the current gcw device.
122 //
123 //--------------------------------------------------------------------------
124 
125 void gcw_init_canvas( GnomeCanvas* canvas )
126 {
127  GcwPLdev* dev = plsc->dev;
128 
129 #ifdef DEBUG_GCW_1
130  gcw_debug( "<gcw_init_canvas>\n" );
131 #endif
132 
133  if ( !GNOME_IS_CANVAS( canvas ) )
134  plexit( "GCW driver: Canvas not found" );
135 
136  // Add the canvas to the device
137  dev->canvas = canvas;
138 
139  // Get the colormap
140  dev->colormap = gtk_widget_get_colormap( GTK_WIDGET( dev->canvas ) );
141 
142  // Size the canvas
143  gcw_set_canvas_size( canvas, dev->width, dev->height );
144 
145  // Create the persistent group, which is always visible
146  if ( !GNOME_IS_CANVAS_ITEM(
147  dev->group_persistent = GNOME_CANVAS_GROUP( gnome_canvas_item_new(
148  gnome_canvas_root( canvas ),
149  gnome_canvas_clipgroup_get_type(),
150  "x", 0.,
151  "y", 0.,
152  NULL ) )
153  ) )
154  {
155  plexit( "GCW driver <gcw_init_canvas>: Canvas group cannot be created" );
156  }
157 
158  // Set the clip to NULL
159  g_object_set( G_OBJECT( dev->group_persistent ), "path", NULL, NULL );
160 
161 #ifdef DEBUG_GCW1
162  gcw_debug( "</gcw_init_canvas>\n" );
163 #endif
164 }
165 
166 
167 //--------------------------------------------------------------------------
168 // gcw_install_canvas()
169 //
170 // Installs a canvas into the current gcw device's window. The canvas is
171 // created if necessary. A variety of callbacks are defined for actions
172 // in the window.
173 //
174 //--------------------------------------------------------------------------
175 
176 //******************************
177 // Main window event callbacks *
178 //*****************************
179 
180 // Delete event callback
181 gint delete_event( GtkWidget *widget, GdkEvent *event, gpointer data )
182 {
183  return FALSE; // FALSE follows with the destroy signal
184 }
185 
186 // Destroy event calback
187 void destroy( GtkWidget *widget, gpointer data )
188 {
189  gtk_main_quit();
190 }
191 
192 //*****************
193 // Zoom callbacks *
194 //****************
195 
196 // All-purpose zoom callback. Referred to by specific zoom callbacks given
197 // below.
198 //
199 void zoom( gpointer data, gint flag )
200 {
201  gint n;
202 
203  GnomeCanvas *canvas;
204  GtkWidget *scrolled_window;
205  GList *list;
206 
207  GcwPLdev * dev = data;
208 
209  gdouble curmag, dum;
210 
211  // Get the current canvas
212  n = gtk_notebook_get_current_page( GTK_NOTEBOOK( dev->notebook ) );
213  scrolled_window = gtk_notebook_get_nth_page( GTK_NOTEBOOK( dev->notebook ), n );
214  canvas = GNOME_CANVAS( gtk_container_get_children(
215  GTK_CONTAINER( gtk_container_get_children(
216  GTK_CONTAINER( scrolled_window ) )->data ) )->data );
217 
218  // Determine the new magnification
219  if ( flag == 2 ) // Zoom in
220  gcw_set_canvas_zoom( canvas, ZOOMSTEP );
221  else if ( flag == 0 ) // Zoom out
222 
223  { // Don't zoom smaller than the original size: this causes GDK pixmap
224  // errors.
225  //
226  gnome_canvas_c2w( canvas, 1, 0, &curmag, &dum );
227  curmag = 1. / curmag;
228  if ( curmag / ZOOMSTEP > 1. )
229  {
230  gcw_set_canvas_zoom( canvas, 1. / ZOOMSTEP );
231  }
232  else
233  {
234  gcw_set_canvas_zoom( canvas, (PLFLT) ( ZOOM100 / curmag ) );
235  }
236  }
237  else // Zoom 100
238  {
239  // Get current magnification
240  gnome_canvas_c2w( canvas, 1, 0, &curmag, &dum );
241  curmag = 1. / curmag;
242  gcw_set_canvas_zoom( canvas, (PLFLT) ( ZOOM100 / curmag ) );
243  }
244 
245  // Set the focus on the notebook
246  gtk_window_set_focus( GTK_WINDOW( dev->window ), dev->notebook );
247 }
248 
249 
250 // Callback when zoom in button is pressed
251 void zoom_in( GtkWidget *widget, gpointer data )
252 {
253  zoom( data, 2 );
254 }
255 
256 // Callback when zoom 100 button is pressed
257 void zoom_100( GtkWidget *widget, gpointer data )
258 {
259  zoom( data, 1 );
260 }
261 
262 // Callback when zoom out button is pressed
263 void zoom_out( GtkWidget *widget, gpointer data )
264 {
265  zoom( data, 0 );
266 }
267 
268 //****************************
269 // File selection callbacks. *
270 //***************************
271 
272 // Callback to OK file selection. Retrieves the selected filename and
273 // replays the plot buffer to it through the associated driver.
274 //
275 void file_ok_sel( GtkWidget *w, gpointer data )
276 {
277  GcwPLdev * dev = data;
278 
279  GtkWidget *scrolled_window;
280  GnomeCanvas *canvas;
281 
282  gchar *fname;
283  guint n;
284  char devname[10], str[100];
285 
286  void *save_state;
287  void *new_state;
288 
289  PLINT cur_strm, new_strm;
290  PLStream *plsr;
291 
292  GtkWidget *fs;
293 
294  gdouble curmag, dum;
295 
296  gboolean errflag = FALSE;
297 
298  struct stat buf;
299 
300  GtkDialog *dialog;
301  GtkWidget *hbox, *message, *icon;
302  gint result;
303 
304  guint context;
305 
306  FILE *f;
307 
308  // Get the file name
309  if ( ( fname =
310  strdup( gtk_file_selection_get_filename( GTK_FILE_SELECTION( dev->filew ) ) ) )
311  == NULL )
312  plabort( "GCW driver <file_ok_sel>: Cannot obtain filename" );
313 
314  // Check to see if the file already exists, and respond appropriately
315  if ( stat( fname, &buf ) == 0 )
316  {
317  // Confirm the user wants to overwrite the existing file
318 
319  dialog = GTK_DIALOG( gtk_dialog_new_with_buttons( "",
320  GTK_WINDOW( dev->filew ),
321  GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
322  GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
323  GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT, NULL ) );
324 
325  message = gtk_label_new( "" );
326  gtk_label_set_markup( GTK_LABEL( message ),
327  "<span size=\"large\"><b>File exists. "
328  "Overwrite?</b></span>" );
329 
330  icon = gtk_image_new_from_stock( GTK_STOCK_DIALOG_QUESTION,
331  GTK_ICON_SIZE_DIALOG );
332 
333  hbox = gtk_hbox_new( FALSE, 0 );
334  gtk_box_pack_start( GTK_BOX( hbox ), icon, TRUE, TRUE, 10 );
335  gtk_box_pack_start( GTK_BOX( hbox ), message, TRUE, TRUE, 10 );
336  gtk_container_add( GTK_CONTAINER( dialog->vbox ), hbox );
337 
338  gtk_widget_show_all( GTK_WIDGET( dialog ) );
339 
340  result = gtk_dialog_run( dialog );
341  gtk_widget_destroy( GTK_WIDGET( dialog ) );
342  if ( result == GTK_RESPONSE_REJECT )
343  return;
344  }
345 
346  // Hide the file selection widget
347  gtk_widget_hide( dev->filew );
348 
349  // Put the focus back on the notebook
350  gtk_window_set_focus( GTK_WINDOW( dev->window ), dev->notebook );
351 
352  // Test that we can open and write to the file
353  if ( ( f = fopen( fname, "w" ) ) == NULL )
354  plabort( "GCW driver <file_ok_sel>: Cannot open output file" );
355  fclose( f );
356  remove( fname ); // Otherwise, we may leave behind a zero-length file
357 
358  // Get the file extension and make sure we recognize it. Allow names
359  // of display devices as well.
360  //
361  // Note that we can't replot to xwin or tk devices, which can't open a
362  // display for some reason.
363  //
364  //
365  n = strlen( fname );
366  if ( strcasecmp( &fname[n - 3], "png" ) == 0 )
367  sprintf( devname, "png" );
368  else if ( strcasecmp( &fname[n - 3], "gif" ) == 0 )
369  sprintf( devname, "gif" );
370  else if ( strcasecmp( &fname[n - 3], "jpg" ) == 0 )
371  sprintf( devname, "jpg" );
372  else if ( strcasecmp( &fname[n - 4], "jpeg" ) == 0 )
373  sprintf( devname, "jpeg" );
374  else if ( strcasecmp( &fname[n - 2], "ps" ) == 0 )
375  sprintf( devname, "ps" );
376  else if ( strcasecmp( &fname[n - 3], "psc" ) == 0 )
377  sprintf( devname, "psc" );
378  else if ( strcasecmp( &fname[n - 4], "xwin" ) == 0 )
379  sprintf( devname, "xwin" );
380  else if ( strcasecmp( &fname[n - 3], "gcw" ) == 0 )
381  sprintf( devname, "gcw" );
382  else if ( strcasecmp( &fname[n - 2], "tk" ) == 0 )
383  sprintf( devname, "tk" );
384  else
385  {
386  if ( dev->statusbar != NULL )
387  {
388  context = gtk_statusbar_get_context_id( GTK_STATUSBAR( dev->statusbar ),
389  "PLplot" );
390  gtk_statusbar_push( GTK_STATUSBAR( dev->statusbar ), context,
391  " WARNING: File type not recognized (unknown "
392  "extension). Use one of ps, psc, png, jpg, or "
393  "gif."
394  );
395  return;
396  }
397  else
398  plabort( "GCW driver <file_ok_sel>: File type not recognized" );
399  }
400 
401  // Check that we are set up appropriately for device
402  if ( strcmp( devname, "ps" ) == 0 || strcmp( devname, "psc" ) == 0 )
403  {
404  if ( plsc->dev_hrshsym != 1 )
405  if ( dev->statusbar != NULL )
406  {
407  context = gtk_statusbar_get_context_id( GTK_STATUSBAR( dev->statusbar ),
408  "PLplot" );
409 
410  gtk_statusbar_push( GTK_STATUSBAR( dev->statusbar ), context,
411  " NOTE: Use '-drvopt hrshsym' on command-line "
412  "for complete symbol set in PostScript files."
413  );
414  }
415  else
416  plwarn( "GCW driver: Use '-drvopt hrshsym' if symbols are missing in "
417  "saved PostScript files." );
418  }
419  if ( strcmp( devname, "xwin" ) == 0 || strcmp( devname, "tk" ) == 0 )
420  {
421  if ( plsc->dev_text != 0 )
422  plwarn( "GCW driver: Use '-drvopt text=0'" );
423  }
424 
425  // Get the current canvas
426  n = gtk_notebook_get_current_page( GTK_NOTEBOOK( dev->notebook ) );
427  scrolled_window = gtk_notebook_get_nth_page( GTK_NOTEBOOK( dev->notebook ), n );
428  canvas = GNOME_CANVAS( gtk_container_get_children(
429  GTK_CONTAINER( gtk_container_get_children(
430  GTK_CONTAINER( scrolled_window ) )->data ) )->data );
431 
432  // Switch in the previously saved plot state
433  new_state = g_object_get_data( G_OBJECT( canvas ), "plotbuf" );
434 
435  if ( new_state != NULL )
436  {
437  save_state = (void *) plbuf_switch( plsc, new_state );
438 
439  plsetopt( "drvopt", "text" ); // Blank out the drvopts (not needed here)
440 
441  // Get the current stream and make a new one
442  plgstrm( &cur_strm );
443  plsr = plsc; // Save a pointer to the current stream
444 
445  plmkstrm( &new_strm );
446  plsfnam( fname ); // Set the file name
447  plsdev( devname ); // Set the device
448 
449  // Copy the current stream to the new stream.
450  plcpstrm( cur_strm, 0 );
451 
452  plreplot(); // do the save by replaying the plot buffer
453 
454  plend1(); // finish the device
455 
456  plsstrm( cur_strm ); // return to previous stream
457 
458  plbuf_restore( plsc, save_state );
459  free( save_state );
460  }
461  else
462  {
463  plwarn( "GCW driver <file_ok_sel>: Cannot set up output stream." );
464  }
465 }
466 
467 // Callback to cancel file selection
468 void file_cancel_sel( GtkWidget *w, gpointer data )
469 {
470  GcwPLdev* dev = data;
471 
472  // Hide the file selection widget
473  gtk_widget_hide( dev->filew );
474 
475  // Put the focus back on the notebook
476  gtk_window_set_focus( GTK_WINDOW( dev->window ), dev->notebook );
477 }
478 
479 // Callback to create file selection dialog
480 void filesel( GtkWidget *widget, gpointer data )
481 {
482  GtkWidget *scrolled_window;
483  GnomeCanvas *canvas;
484 
485  GcwPLdev * dev = data;
486 
487  guint n;
488 
489  // Get the current canvas
490  n = gtk_notebook_get_current_page( GTK_NOTEBOOK( dev->notebook ) );
491  scrolled_window = gtk_notebook_get_nth_page( GTK_NOTEBOOK( dev->notebook ), n );
492  canvas = GNOME_CANVAS( gtk_container_get_children(
493  GTK_CONTAINER( gtk_container_get_children(
494  GTK_CONTAINER( scrolled_window ) )->data ) )->data );
495 
496  // Create a new file dialog if it doesn't already exist
497  if ( dev->filew == NULL )
498  {
499  // Create a new file selection widget
500  dev->filew = gtk_file_selection_new( "File selection" );
501 
502  // Connect the ok_button to file_ok_sel function
503  g_signal_connect( G_OBJECT( GTK_FILE_SELECTION( dev->filew )->ok_button ),
504  "clicked", G_CALLBACK( file_ok_sel ), (gpointer) dev );
505 
506  // Connect the cancel_button to destroy the widget
507  g_signal_connect( G_OBJECT( GTK_FILE_SELECTION( dev->filew )->cancel_button ),
508  "clicked", G_CALLBACK( file_cancel_sel ), (gpointer) dev );
509 
510  // Lets set the filename, as if this were a save dialog, and we are giving
511  // a default filename
512  gtk_file_selection_set_filename( GTK_FILE_SELECTION( dev->filew ),
513  "plot.psc" );
514  }
515 
516  gtk_widget_show( dev->filew );
517 }
518 
519 //*************************
520 // Key release callbacks. *
521 //************************
522 
523 void key_release( GtkWidget *widget, GdkEventKey *event, gpointer data )
524 {
525  if ( event->keyval == '+' )
526  zoom( data, 2 );
527  if ( event->keyval == '=' )
528  zoom( data, 1 );
529  if ( event->keyval == '-' )
530  zoom( data, 0 );
531  if ( event->keyval == 'q' )
532  destroy( widget, data );
533 }
534 
535 //*********************
536 // gcw_install_canvas *
537 //********************
538 
539 void gcw_install_canvas( GnomeCanvas *canvas )
540 {
541  GcwPLdev * dev = plsc->dev;
542  GtkWidget *vbox, *hbox, *button, *image, *scrolled_window;
543 
544  gboolean flag = FALSE;
545 
546  PLINT width, height;
547 
548 #ifdef DEBUG_GCW_1
549  gcw_debug( "<gcw_install_canvas>\n" );
550 #endif
551 
552  // Create a new canvas if needed
553  if ( !GNOME_IS_CANVAS( canvas ) )
554  {
555  if ( !GNOME_IS_CANVAS( canvas = GNOME_CANVAS( gnome_canvas_new_aa() ) ) )
556  plexit( "GCW driver <gcw_install_canvas>: Could not create Canvas" );
557  }
558 
559  // Initialize canvas
560  gcw_init_canvas( canvas );
561 
562  if ( dev->window == NULL ) // Create a new window and install a notebook
563 
564  {
565  flag = TRUE;
566 
567  // Create a new window
568  dev->window = gtk_window_new( GTK_WINDOW_TOPLEVEL );
569  gtk_window_set_title( GTK_WINDOW( dev->window ), "PLplot" );
570 
571  // Connect the signal handlers to the window decorations
572  g_signal_connect( G_OBJECT( dev->window ), "delete_event",
573  G_CALLBACK( delete_event ), NULL );
574  g_signal_connect( G_OBJECT( dev->window ), "destroy", G_CALLBACK( destroy ), NULL );
575 
576 
577  // Create a vbox and put it into the window
578  vbox = gtk_vbox_new( FALSE, 2 );
579  gtk_container_add( GTK_CONTAINER( dev->window ), vbox );
580 
581  // Create a hbox and put it into the vbox
582  hbox = gtk_hbox_new( FALSE, 0 );
583  gtk_box_pack_start( GTK_BOX( vbox ), hbox, TRUE, TRUE, 0 );
584 
585  // Create a statusbar and put it into the vbox
586  dev->statusbar = gtk_statusbar_new();
587  gtk_box_pack_start( GTK_BOX( vbox ), dev->statusbar, FALSE, FALSE, 0 );
588 
589  // Add an vbox to the hbox
590  vbox = gtk_vbox_new( FALSE, 5 );
591  gtk_container_set_border_width( GTK_CONTAINER( vbox ), 5 );
592  gtk_box_pack_start( GTK_BOX( hbox ), vbox, FALSE, FALSE, 0 );
593 
594  // Create the new notebook and add it to the hbox
595  dev->notebook = gtk_notebook_new();
596  gtk_notebook_set_scrollable( GTK_NOTEBOOK( dev->notebook ), TRUE );
597  gtk_box_pack_start( GTK_BOX( hbox ), dev->notebook, TRUE, TRUE, 0 );
598  g_signal_connect( G_OBJECT( dev->notebook ), "key_release_event",
599  G_CALLBACK( key_release ), G_OBJECT( dev->notebook ) );
600 
601  // Use a few labels as spacers
602  gtk_box_pack_start( GTK_BOX( vbox ), gtk_label_new( " " ), FALSE, FALSE, 0 );
603  gtk_box_pack_start( GTK_BOX( vbox ), gtk_label_new( " " ), FALSE, FALSE, 0 );
604 
605  // Add buttons to the vbox
606 
607  // Add zoom in button and create callbacks
608  image = gtk_image_new_from_stock( GTK_STOCK_ZOOM_IN,
609  GTK_ICON_SIZE_SMALL_TOOLBAR );
610  button = gtk_button_new();
611  gtk_container_add( GTK_CONTAINER( button ), image );
612  gtk_box_pack_start( GTK_BOX( vbox ), button, FALSE, FALSE, 0 );
613  g_signal_connect( G_OBJECT( button ), "clicked",
614  G_CALLBACK( zoom_in ), (gpointer) dev );
615  g_signal_connect( G_OBJECT( button ), "key_release_event",
616  G_CALLBACK( key_release ), (gpointer) dev );
617 
618  // Add zoom100 button and create callbacks
619  image = gtk_image_new_from_stock( GTK_STOCK_ZOOM_100,
620  GTK_ICON_SIZE_SMALL_TOOLBAR );
621  button = gtk_button_new();
622  gtk_container_add( GTK_CONTAINER( button ), image );
623  gtk_box_pack_start( GTK_BOX( vbox ), button, FALSE, FALSE, 0 );
624  g_signal_connect( G_OBJECT( button ), "clicked",
625  G_CALLBACK( zoom_100 ), (gpointer) dev );
626 
627  // Add zoom out button and create callbacks
628  image = gtk_image_new_from_stock( GTK_STOCK_ZOOM_OUT,
629  GTK_ICON_SIZE_SMALL_TOOLBAR );
630  button = gtk_button_new();
631  gtk_container_add( GTK_CONTAINER( button ), image );
632  gtk_box_pack_start( GTK_BOX( vbox ), button, FALSE, FALSE, 0 );
633  g_signal_connect( G_OBJECT( button ), "clicked",
634  G_CALLBACK( zoom_out ), (gpointer) dev );
635  g_signal_connect( G_OBJECT( button ), "key_release_event",
636  G_CALLBACK( key_release ), (gpointer) dev );
637 
638  // Add save button and create callbacks
639  if ( plsc->plbuf_write )
640  {
641  image = gtk_image_new_from_stock( GTK_STOCK_SAVE,
642  GTK_ICON_SIZE_SMALL_TOOLBAR );
643  button = gtk_button_new();
644  gtk_container_add( GTK_CONTAINER( button ), image );
645  gtk_box_pack_start( GTK_BOX( vbox ), button, FALSE, FALSE, 0 );
646  g_signal_connect( G_OBJECT( button ), "clicked",
647  G_CALLBACK( filesel ), (gpointer) dev );
648  }
649  } // if(dev->window==NULL)
650 
651  // Put the canvas in a scrolled window
652  scrolled_window = gtk_scrolled_window_new( NULL, NULL );
653  gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW( scrolled_window ),
654  GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC );
655  gtk_scrolled_window_add_with_viewport( GTK_SCROLLED_WINDOW( scrolled_window ),
656  GTK_WIDGET( canvas ) );
657 
658  // Install the scrolled window in the notebook
659  gtk_notebook_append_page( GTK_NOTEBOOK( dev->notebook ), scrolled_window, NULL );
660 
661  if ( flag )
662  {
663  // Set the focus on the notebook
664  gtk_window_set_focus( GTK_WINDOW( dev->window ), dev->notebook );
665 
666  // Retrieve the canvas width and height
667  width = *(PLINT *) g_object_get_data( G_OBJECT( canvas ), "canvas-width" );
668  height = *(PLINT *) g_object_get_data( G_OBJECT( canvas ), "canvas-height" );
669 
670  // Size the window
671  gtk_window_resize( GTK_WINDOW( dev->window ), width * ZOOM100 + 65,
672  height * ZOOM100 + 75 );
673  }
674 
675  // Display everything
676  gtk_widget_show_all( dev->window );
677 
678 #ifdef DEBUG_GCW_1
679  gcw_debug( "</gcw_install_canvas>\n" );
680 #endif
681 }
682 
683 
684 //--------------------------------------------------------------------------
685 // gcw_set_device_size()
686 //
687 // Sets the page size for this device.
688 //
689 // Width and height are both measured in device coordinate units.
690 //
691 // Note that coordinates in driver-space are measured in device units,
692 // which correspond to the pixel size on a typical screen. The coordinates
693 // reported and received from the PLplot core, however, are in virtual
694 // coordinates, which is just a scaled version of the device coordinates.
695 // This strategy is used so that the calculations in the PLplot
696 // core are performed at reasonably high resolution.
697 //
698 //--------------------------------------------------------------------------
699 
700 void gcw_set_device_size( PLINT width, PLINT height )
701 {
702  GcwPLdev* dev = plsc->dev;
703  PLINT w, h;
704 
705  // Set the number of virtual coordinate units per mm
706  plP_setpxl( (PLFLT) VIRTUAL_PIXELS_PER_MM, (PLFLT) VIRTUAL_PIXELS_PER_MM );
707 
708  // Set up physical limits of plotting device, in virtual coord units
709  w = (PLINT) ( width * VSCALE );
710  h = (PLINT) ( height * VSCALE );
711  plP_setphy( (PLINT) 0, w, (PLINT) 0, h );
712 
713  // Save the width and height for the device, in device units
714  dev->width = width;
715  dev->height = height;
716 }
717 
718 //--------------------------------------------------------------------------
719 // gcw_set_canvas_size()
720 //
721 // Sets the canvas size. If resizing is not allowed, this function
722 // ensures that the canvas size matches the physical page size.
723 //
724 //--------------------------------------------------------------------------
725 
726 gint count = 0;
727 
728 void gcw_set_canvas_size( GnomeCanvas* canvas, PLINT width, PLINT height )
729 {
730  GcwPLdev * dev = plsc->dev;
731  PLINT tmp;
732 
733  PLINT *w, *h;
734 
735  GdkGC *gc_new;
736  GdkGCValues values;
737 
738  PLINT strm;
739 
740  GdkPixmap *background;
741 
742 #ifdef DEBUG_GCW_1
743  gcw_debug( "<gcw_set_canvas_size>\n" );
744 #endif
745 
746  // Set the device size, if resizing is allowed.
747  if ( dev->allow_resize )
748  gcw_set_device_size( width, height );
749 
750  width = dev->width;
751  height = dev->height;
752  if ( plsc->portrait ) // Swap width and height of display
753  {
754  tmp = width;
755  width = height;
756  height = tmp;
757  }
758 
759  // The width and height need to be enlarged by 1 pixel for the canvas
760  width += 1;
761  height += 1;
762 
763  // Attach the width and height to the canvas
764  if ( ( w = (PLINT *) malloc( sizeof ( gint ) ) ) == NULL )
765  plwarn( "GCW driver <gcw_set_canvas_size>: Insufficient memory." );
766  if ( ( h = (PLINT *) malloc( sizeof ( gint ) ) ) == NULL )
767  plwarn( "GCW driver <gcw_set_canvas_size>: Insufficient memory." );
768  *w = width;
769  *h = height;
770  g_object_set_data( G_OBJECT( canvas ), "canvas-width", (gpointer) w );
771  g_object_set_data( G_OBJECT( canvas ), "canvas-height", (gpointer) h );
772 
773  // Size the canvas appropriately
774  gtk_widget_set_size_request( GTK_WIDGET( canvas ), (gint) ( width ),
775  (gint) ( height ) );
776 
777  // Position the canvas appropriately
778  gnome_canvas_set_scroll_region( canvas, 0., (gdouble) ( -height ),
779  (gdouble) ( width ), 1. );
780 
781  // Set up the background pixmap
782  if ( dev->background == NULL || dev->allow_resize )
783  {
784  if ( GDK_IS_PIXMAP( dev->background ) )
785  g_object_unref( dev->background );
786 
787  // Why does this next *useless* command speed up the animation demo?
788  // If we unref the allocated pixmaps, the benefit goes away!!
789 // if(count<2) {
790 // gdk_pixmap_new(NULL,width,height,gdk_visual_get_best_depth());
791 // printf("Count %d\n",count);
792 // count++;
793 // }
794 // else { printf("Count %d\n",count); count ++; }
795 
796  dev->background = gdk_pixmap_new( NULL, width, height,
797  gtk_widget_get_visual( GTK_WIDGET( canvas ) )->depth );
798  }
799 
800  // Set up the drawing context for the background pixmap
801  if ( dev->gc == NULL || dev->allow_resize )
802  {
803  // Maintain the old values for pen width, color, etc
804  if ( GDK_IS_GC( dev->gc ) )
805  {
806  gdk_gc_get_values( dev->gc, &values );
807  gdk_gc_unref( dev->gc );
808  dev->gc = gdk_gc_new_with_values( dev->background, &values,
809  GDK_GC_FOREGROUND | GDK_GC_LINE_WIDTH |
810  GDK_GC_LINE_STYLE | GDK_GC_CAP_STYLE |
811  GDK_GC_JOIN_STYLE );
812  }
813  else
814  dev->gc = gdk_gc_new( dev->background );
815  }
816 
817  // Clear the background pixmap
818  gcw_clear_background( dev );
819 
820  // Advance the page if we are allowing resizing. This ensures that
821  // the physical coordinate system is set up correctly.
822  //
823  if ( dev->allow_resize )
824  pladv( 0 );
825 
826 #ifdef DEBUG_GCW_1
827  gcw_debug( "</gcw_set_canvas_size>\n" );
828 #endif
829 }
830 
831 
832 //--------------------------------------------------------------------------
833 // gcw_set_canvas_zoom()
834 //
835 // Sets the zoom magnification on the canvas and resizes the widget
836 // appropriately.
837 //--------------------------------------------------------------------------
838 
839 void gcw_set_canvas_zoom( GnomeCanvas* canvas, PLFLT magnification )
840 {
841  gdouble curmag = 1., dum;
842 
843  PLINT width, height;
844 
845 #ifdef DEBUG_GCW_1
846  gcw_debug( "<gcw_set_canvas_zoom>\n" );
847 #endif
848 
849  // Retrieve the device width and height
850  width = *(PLINT *) g_object_get_data( G_OBJECT( canvas ), "canvas-width" );
851  height = *(PLINT *) g_object_get_data( G_OBJECT( canvas ), "canvas-height" );
852 
853  // Get the current magnification
854  gnome_canvas_c2w( canvas, 1, 0, &curmag, &dum );
855  curmag = 1. / curmag;
856 
857  // Apply the new magnification
858  gnome_canvas_set_pixels_per_unit( canvas, magnification * curmag );
859 
860  // Size the canvas appropriately
861  gtk_widget_set_size_request( GTK_WIDGET( canvas ),
862  (gint) ( ( width ) * magnification * curmag ),
863  (gint) ( ( height ) * magnification * curmag ) );
864 
865  // Position the canvas appropriately
866  gnome_canvas_set_scroll_region( canvas, 0., (gdouble) ( -height ),
867  (gdouble) ( width ), 1. );
868 
869 #ifdef DEBUG_GCW_1
870  gcw_debug( "</gcw_set_canvas_zoom>\n" );
871 #endif
872 }
873 
874 
875 //--------------------------------------------------------------------------
876 // gcw_use_text()
877 //
878 // Used to turn text usage on and off for the current device.
879 //--------------------------------------------------------------------------
880 
881 void gcw_use_text( PLINT use_text )
882 {
883  GcwPLdev* dev = plsc->dev;
884 
885 #ifdef DEBUG_GCW_1
886  gcw_debug( "<gcw_use_text>\n" );
887 #endif
888 
889 #ifdef PL_HAVE_FREETYPE
890 
891  if ( use_text )
892  plsc->dev_text = 1; // Allow text handling
893  else
894  plsc->dev_text = 0; // Disallow text handling
895 
896 #endif
897 
898 #ifdef DEBUG_GCW_1
899  gcw_debug( "</gcw_use_text>\n" );
900 #endif
901 }
902 
903 
904 //--------------------------------------------------------------------------
905 // gcw_use_pixmap()
906 //
907 // Used to turn pixmap usage on and off for the current device.
908 // This is relevant for polygon fills (used during shading calls).
909 //--------------------------------------------------------------------------
910 
911 void gcw_use_pixmap( PLINT use_pixmap )
912 {
913  GcwPLdev* dev = plsc->dev;
914 
915 #ifdef DEBUG_GCW_1
916  gcw_debug( "<gcw_use_pixmap>\n" );
917 #endif
918 
919  dev->use_pixmap = (gboolean) use_pixmap;
920 
921 #ifdef DEBUG_GCW_1
922  gcw_debug( "</gcw_use_pixmap>\n" );
923 #endif
924 }
925 
926 
927 //--------------------------------------------------------------------------
928 // gcw_use_hrshsym()
929 //
930 // Used to turn hershey symbol usage on and off for the current device.
931 //--------------------------------------------------------------------------
932 
933 void gcw_use_hrshsym( PLINT use_hrshsym )
934 {
935  GcwPLdev* dev = plsc->dev;
936 
937 #ifdef DEBUG_GCW_1
938  gcw_debug( "<gcw_use_hrshsym>\n" );
939 #endif
940 
941  plsc->dev_hrshsym = use_hrshsym;
942 
943 #ifdef DEBUG_GCW_1
944  gcw_debug( "</gcw_use_hrshsym>\n" );
945 #endif
946 }
947 
948 
949 //--------------------------------------------------------------------------
950 // gcw_use_persistence
951 //
952 // Directs the GCW driver whether or not the subsequent drawing operations
953 // should be persistent.
954 //--------------------------------------------------------------------------
955 
956 void gcw_use_persistence( PLINT use_persistence )
957 {
958  GcwPLdev* dev = plsc->dev;
959 
960 #ifdef DEBUG_GCW_1
961  gcw_debug( "<gcw_use_persistence>\n" );
962 #endif
963 
964  dev->use_persistence = (gboolean) use_persistence;
965 
966 #ifdef DEBUG_GCW_1
967  gcw_debug( "</gcw_use_persistence>\n" );
968 #endif
969 }