1 /* main processing window
2 */
3
4 /*
5
6 Copyright (C) 1991-2003 The National Gallery
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License along
19 with this program; if not, write to the Free Software Foundation, Inc.,
20 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21
22 */
23
24 /*
25
26 These files are distributed with VIPS - http://www.vips.ecs.soton.ac.uk
27
28 */
29
30 #include "ip.h"
31
32 /*
33 #define DEBUG
34 */
35
36 /* Load and save recent items here.
37 */
38 #define RECENT_WORKSPACE "recent_workspace"
39 #define RECENT_IMAGE "recent_image"
40 #define RECENT_MATRIX "recent_matrix"
41
42 /* Recently loaded/saved workspaces, images and matricies.
43 */
44 GSList *mainw_recent_workspace = NULL;
45 GSList *mainw_recent_image = NULL;
46 GSList *mainw_recent_matrix = NULL;
47
48 /* Auto-recalc state. Don't do this as a preference, since preferences are
49 * workspaces and need to have recalc working to operate.
50 */
51 gboolean mainw_auto_recalc = TRUE;
52
53 static gint mainw_layout_timeout = 0;
54
55 static iWindowClass *parent_class = NULL;
56
57 /* All the mainw.
58 */
59 static GSList *mainw_all = NULL;
60
61 void
mainw_startup(void)62 mainw_startup( void )
63 {
64 IM_FREEF( recent_free, mainw_recent_workspace );
65 IM_FREEF( recent_free, mainw_recent_image );
66 IM_FREEF( recent_free, mainw_recent_matrix );
67
68 mainw_recent_workspace = recent_load( RECENT_WORKSPACE );
69 mainw_recent_image = recent_load( RECENT_IMAGE );
70 mainw_recent_matrix = recent_load( RECENT_MATRIX );
71 }
72
73 void
mainw_shutdown(void)74 mainw_shutdown( void )
75 {
76 recent_save( mainw_recent_workspace, RECENT_WORKSPACE );
77 recent_save( mainw_recent_image, RECENT_IMAGE );
78 recent_save( mainw_recent_matrix, RECENT_MATRIX );
79
80 IM_FREEF( recent_free, mainw_recent_workspace );
81 IM_FREEF( recent_free, mainw_recent_image );
82 IM_FREEF( recent_free, mainw_recent_matrix );
83 }
84
85 static int mainw_recent_freeze_count = 0;
86
87 void
mainw_recent_freeze(void)88 mainw_recent_freeze( void )
89 {
90 mainw_recent_freeze_count += 1;
91 }
92
93 void
mainw_recent_thaw(void)94 mainw_recent_thaw( void )
95 {
96 g_assert( mainw_recent_freeze_count > 0 );
97
98 mainw_recent_freeze_count -= 1;
99 }
100
101 void
mainw_recent_add(GSList ** recent,const char * filename)102 mainw_recent_add( GSList **recent, const char *filename )
103 {
104 if( !mainw_recent_freeze_count ) {
105 char buf[FILENAME_MAX];
106
107 im_strncpy( buf, PATH_TMP, FILENAME_MAX );
108 path_expand( buf );
109
110 if( filename &&
111 strcmp( filename, "" ) != 0 &&
112 !is_prefix( buf, filename ) )
113 *recent = recent_add( *recent, filename );
114 }
115 }
116
117 /* Pick a mainw at random. Used if we need a window for a dialog, and we're
118 * not sure which to pick.
119 */
120 Mainw *
mainw_pick_one(void)121 mainw_pick_one( void )
122 {
123 if( !mainw_all )
124 /* Must be a cast here, since iwindow_pick_one() can return
125 * NULL during shutdown.
126 */
127 return( (Mainw *) iwindow_pick_one() );
128
129 return( MAINW( mainw_all->data ) );
130 }
131
132 static void
mainw_finalize(GObject * gobject)133 mainw_finalize( GObject *gobject )
134 {
135 #ifdef DEBUG
136 printf( "mainw_finalize: %p\n", gobject );
137 #endif /*DEBUG*/
138
139 g_return_if_fail( gobject != NULL );
140 g_return_if_fail( IS_MAINW( gobject ) );
141
142 G_OBJECT_CLASS( parent_class )->finalize( gobject );
143 }
144
145 static void
mainw_dispose(GObject * object)146 mainw_dispose( GObject *object )
147 {
148 Mainw *mainw;
149
150 g_return_if_fail( object != NULL );
151 g_return_if_fail( IS_MAINW( object ) );
152
153 mainw = MAINW( object );
154
155 #ifdef DEBUG
156 printf( "mainw_dispose\n" );
157 #endif /*DEBUG*/
158
159 IM_FREEF( g_source_remove, mainw->refresh_timeout );
160
161 FREESID( mainw->changed_sid, mainw->wsg );
162
163 FREESID( mainw->imageinfo_changed_sid, main_imageinfogroup );
164 FREESID( mainw->heap_changed_sid, reduce_context->heap );
165 FREESID( mainw->watch_changed_sid, main_watchgroup );
166
167 FREESID( mainw->begin_sid, progress_get() );
168 FREESID( mainw->update_sid, progress_get() );
169 FREESID( mainw->end_sid, progress_get() );
170
171 UNREF( mainw->kitgview );
172
173 /* We don't unref wsg: it's destroyed by mainw_popdown() with
174 * filemodel_inter_savenclose_cb().
175 */
176
177 mainw_all = g_slist_remove( mainw_all, mainw );
178
179 G_OBJECT_CLASS( parent_class )->dispose( object );
180 }
181
182 static void *
mainw_configure_event_sub(Workspace * ws,GdkEventConfigure * event)183 mainw_configure_event_sub( Workspace *ws, GdkEventConfigure *event )
184 {
185 MODEL( ws )->window_x = event->x;
186 MODEL( ws )->window_y = event->y;
187 MODEL( ws )->window_width = event->width;
188 MODEL( ws )->window_height = event->height;
189
190 return( NULL );
191 }
192
193 static gboolean
mainw_configure_event(GtkWidget * widget,GdkEventConfigure * event)194 mainw_configure_event( GtkWidget *widget, GdkEventConfigure *event )
195 {
196 Mainw *mainw = MAINW( widget );
197
198 /* We have to record on all wses, since we don't know which will be
199 * first on reload.
200 */
201 workspacegroup_map( mainw->wsg,
202 (workspace_map_fn) mainw_configure_event_sub, event, NULL );
203
204 return( GTK_WIDGET_CLASS( parent_class )->
205 configure_event( widget, event ) );
206 }
207
208 static void
mainw_class_init(MainwClass * class)209 mainw_class_init( MainwClass *class )
210 {
211 GObjectClass *gobject_class = G_OBJECT_CLASS( class );
212 GtkWidgetClass *widget_class = (GtkWidgetClass *) class;
213
214 parent_class = g_type_class_peek_parent( class );
215
216 gobject_class->finalize = mainw_finalize;
217 gobject_class->dispose = mainw_dispose;
218
219 widget_class->configure_event = mainw_configure_event;
220 }
221
222 static void
mainw_progress_begin(Progress * progress,Mainw * mainw)223 mainw_progress_begin( Progress *progress, Mainw *mainw )
224 {
225 mainw->cancel = FALSE;
226 gtk_widget_show( mainw->progress_box );
227 }
228
229 static void
mainw_progress_update(Progress * progress,gboolean * cancel,Mainw * mainw)230 mainw_progress_update( Progress *progress, gboolean *cancel, Mainw *mainw )
231 {
232 gtk_progress_bar_set_text( GTK_PROGRESS_BAR( mainw->progress ),
233 vips_buf_all( &progress->feedback ) );
234 gtk_progress_bar_set_fraction( GTK_PROGRESS_BAR( mainw->progress ),
235 IM_CLIP( 0.0, (double) progress->percent / 100.0, 1.0 ) );
236
237 if( mainw->cancel )
238 *cancel = TRUE;
239 }
240
241 static void
mainw_progress_end(Progress * progress,Mainw * mainw)242 mainw_progress_end( Progress *progress, Mainw *mainw )
243 {
244 gtk_widget_hide( mainw->progress_box );
245 mainw->cancel = FALSE;
246 }
247
248 static void
mainw_init(Mainw * mainw)249 mainw_init( Mainw *mainw )
250 {
251 mainw->wsg = NULL;
252
253 mainw->changed_sid = 0;
254
255 mainw->imageinfo_changed_sid = 0;
256 mainw->heap_changed_sid = 0;
257 mainw->watch_changed_sid = 0;
258
259 mainw->begin_sid = g_signal_connect( progress_get(), "begin",
260 G_CALLBACK( mainw_progress_begin ), mainw );
261 mainw->update_sid = g_signal_connect( progress_get(), "update",
262 G_CALLBACK( mainw_progress_update ), mainw );
263 mainw->end_sid = g_signal_connect( progress_get(), "end",
264 G_CALLBACK( mainw_progress_end ), mainw );
265 mainw->cancel = FALSE;
266
267 mainw->free_type = FALSE;
268
269 mainw->toolbar_visible = MAINW_TOOLBAR;
270 mainw->statusbar_visible = MAINW_STATUSBAR;
271
272 mainw->kitgview = NULL;
273 mainw->toolbar = NULL;
274
275 mainw->statusbar_main = NULL;
276 mainw->statusbar = NULL;
277 mainw->space_free = NULL;
278 mainw->space_free_eb = NULL;
279 mainw->progress_box = NULL;
280 mainw->progress = NULL;
281
282 mainw_all = g_slist_prepend( mainw_all, mainw );
283 }
284
285 GType
mainw_get_type(void)286 mainw_get_type( void )
287 {
288 static GType type = 0;
289
290 if( !type ) {
291 static const GTypeInfo info = {
292 sizeof( MainwClass ),
293 NULL, /* base_init */
294 NULL, /* base_finalize */
295 (GClassInitFunc) mainw_class_init,
296 NULL, /* class_finalize */
297 NULL, /* class_data */
298 sizeof( Mainw ),
299 32, /* n_preallocs */
300 (GInstanceInitFunc) mainw_init,
301 };
302
303 type = g_type_register_static( TYPE_IWINDOW,
304 "Mainw", &info, 0 );
305 }
306
307 return( type );
308 }
309
310 static void
mainw_cancel_cb(GtkWidget * wid,Mainw * mainw)311 mainw_cancel_cb( GtkWidget *wid, Mainw *mainw )
312 {
313 mainw->cancel = TRUE;
314 }
315
316 void
mainw_find_disc(VipsBuf * buf)317 mainw_find_disc( VipsBuf *buf )
318 {
319 double sz = find_space( PATH_TMP );
320
321 if( sz < 0 )
322 vips_buf_appendf( buf, _( "No temp area" ) );
323 else {
324 char txt[MAX_STRSIZE];
325 VipsBuf buf2 = VIPS_BUF_STATIC( txt );
326
327 vips_buf_append_size( &buf2, sz );
328 vips_buf_appendf( buf, _( "%s free" ), vips_buf_all( &buf2 ) );
329 }
330 }
331
332 void
mainw_find_heap(VipsBuf * buf,Heap * heap)333 mainw_find_heap( VipsBuf *buf, Heap *heap )
334 {
335 /* How much we can still expand the heap by ... this
336 * can be -ve if we've closed a workspace, or changed
337 * the upper limit.
338 */
339 int togo = IM_MAX( 0, (heap->mxb - heap->nb) * heap->rsz );
340
341 vips_buf_appendf( buf, _( "%d cells free" ), heap->nfree + togo );
342 }
343
344 Workspace *
mainw_get_workspace(Mainw * mainw)345 mainw_get_workspace( Mainw *mainw )
346 {
347 Workspace *ws;
348
349 if( mainw->wsg &&
350 (ws = WORKSPACE( ICONTAINER( mainw->wsg )->current )) )
351 return( ws );
352
353 return( NULL );
354 }
355
356 Workspace *
mainw_next_workspace(Mainw * mainw)357 mainw_next_workspace( Mainw *mainw )
358 {
359 Workspace *ws;
360
361 if( mainw->wsg &&
362 (ws = WORKSPACE(
363 icontainer_next( ICONTAINER( mainw->wsg ) ) )) )
364 return( ws );
365
366 return( NULL );
367 }
368
369 /* Update the space remaining indicator.
370 */
371 static void
mainw_free_update(Mainw * mainw)372 mainw_free_update( Mainw *mainw )
373 {
374 Heap *heap = reduce_context->heap;
375 char txt[80];
376 VipsBuf buf = VIPS_BUF_STATIC( txt );
377 Workspace *ws;
378
379 if( (ws = mainw_get_workspace( mainw )) &&
380 workspace_selected_any( ws ) ) {
381 vips_buf_appends( &buf, _( "Selected:" ) );
382 vips_buf_appends( &buf, " " );
383 workspace_selected_names( ws, &buf, ", " );
384 }
385 else {
386 /* Out of space? Make sure we swap to cell display.
387 */
388 if( !heap->free )
389 mainw->free_type = FALSE;
390
391 if( mainw->free_type )
392 mainw_find_heap( &buf, heap );
393 else
394 mainw_find_disc( &buf );
395 }
396
397 set_glabel( mainw->space_free, "%s", vips_buf_all( &buf ) );
398 }
399
400 static void
mainw_title_update(Mainw * mainw)401 mainw_title_update( Mainw *mainw )
402 {
403 Workspace *ws;
404 char txt[512];
405 VipsBuf buf = VIPS_BUF_STATIC( txt );
406 char *filename;
407
408 if( mainw->wsg &&
409 FILEMODEL( mainw->wsg )->modified )
410 vips_buf_appendf( &buf, "*" );
411
412 if( mainw->wsg &&
413 (filename = FILEMODEL( mainw->wsg )->filename) ) {
414 char *base = g_path_get_basename( filename );
415 char *dir = g_path_get_dirname( filename );
416
417 vips_buf_appendf( &buf, "%s (%s)", base, dir );
418
419 g_free( base );
420 g_free( dir );
421 }
422 else
423 vips_buf_appends( &buf, _( "unsaved workspace" ) );
424
425 if( (ws = mainw_get_workspace( mainw )) ) {
426 vips_buf_appends( &buf, " - " );
427 vips_buf_appendf( &buf, "%s", NN( IOBJECT( ws->sym )->name ) );
428 if( ws->compat_major ) {
429 vips_buf_appends( &buf, " - " );
430 vips_buf_appends( &buf, _( "compatibility mode" ) );
431 vips_buf_appendf( &buf, " %d.%d",
432 ws->compat_major,
433 ws->compat_minor );
434 }
435 }
436
437 vips_buf_appendf( &buf, " - %s", PACKAGE );
438
439 iwindow_set_title( IWINDOW( mainw ), "%s", vips_buf_all( &buf ) );
440 }
441
442 static void
mainw_status_update(Mainw * mainw)443 mainw_status_update( Mainw *mainw )
444 {
445 Workspace *ws;
446
447 if( (ws = mainw_get_workspace( mainw )) &&
448 ws->status )
449 gtk_label_set_text( GTK_LABEL( mainw->statusbar ), ws->status );
450 else {
451 char txt[256];
452
453 im_snprintf( txt, 256, _( NIP_COPYRIGHT ), PACKAGE );
454 gtk_label_set_markup( GTK_LABEL( mainw->statusbar ), txt );
455 }
456 }
457
458 static gboolean
mainw_refresh_timeout_cb(gpointer user_data)459 mainw_refresh_timeout_cb( gpointer user_data )
460 {
461 static GtkToolbarStyle styles[] = {
462 0, /* Overwrite with system default */
463 GTK_TOOLBAR_ICONS,
464 GTK_TOOLBAR_TEXT,
465 GTK_TOOLBAR_BOTH,
466 GTK_TOOLBAR_BOTH_HORIZ
467 };
468 static gboolean inited_default_style = FALSE;
469
470 /* Keep in step with the WorkspaceMode enum.
471 */
472 const static char *view_mode[] = {
473 "Normal",
474 "ShowFormula",
475 "NoEdit"
476 };
477
478 Mainw *mainw = MAINW( user_data );
479 iWindow *iwnd = IWINDOW( mainw );
480 int pref = IM_CLIP( 0, MAINW_TOOLBAR_STYLE, IM_NUMBER( styles ) - 1 );
481
482 GtkAction *action;
483 Workspace *ws;
484
485 #ifdef DEBUG
486 printf( "mainw_refresh_timeout_cb: %p\n", mainw );
487 #endif /*DEBUG*/
488
489 mainw->refresh_timeout = 0;
490
491 mainw_status_update( mainw );
492 mainw_free_update( mainw );
493 mainw_title_update( mainw );
494
495 if( !inited_default_style ) {
496 styles[0] =
497 gtk_toolbar_get_style( GTK_TOOLBAR( mainw->toolbar ) );
498 inited_default_style = TRUE;
499 }
500
501 gtk_toolbar_set_style( GTK_TOOLBAR( mainw->toolbar ), styles[pref] );
502
503 action = gtk_action_group_get_action( iwnd->action_group,
504 "AutoRecalculate" );
505 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION( action ),
506 mainw_auto_recalc );
507
508 action = gtk_action_group_get_action( iwnd->action_group,
509 "Toolbar" );
510 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION( action ),
511 mainw->toolbar_visible );
512 widget_visible( mainw->toolbar, mainw->toolbar_visible );
513
514 action = gtk_action_group_get_action( iwnd->action_group,
515 "Statusbar" );
516 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION( action ),
517 mainw->statusbar_visible );
518 widget_visible( mainw->statusbar_main, mainw->statusbar_visible );
519
520 if( (ws = mainw_get_workspace( mainw )) ) {
521 action = gtk_action_group_get_action( iwnd->action_group,
522 "Lock" );
523 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION( action ),
524 ws->locked );
525
526 action = gtk_action_group_get_action( iwnd->action_group,
527 "Tabdefs" );
528 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION( action ),
529 ws->lpane_open );
530
531 action = gtk_action_group_get_action( iwnd->action_group,
532 "ToolkitBrowser" );
533 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION( action ),
534 ws->rpane_open );
535
536 action = gtk_action_group_get_action( iwnd->action_group,
537 view_mode[ws->mode] );
538 gtk_toggle_action_set_active( GTK_TOGGLE_ACTION( action ),
539 TRUE );
540
541 workspace_jump_update( ws, mainw->jump_to_column_menu );
542
543 if( mainw->kitg != ws->kitg ) {
544 UNREF( mainw->kitgview );
545
546 mainw->kitgview = TOOLKITGROUPVIEW(
547 model_view_new( MODEL( ws->kitg ), NULL ) );
548 g_object_ref( G_OBJECT( mainw->kitgview ) );
549 gtk_object_sink( GTK_OBJECT( mainw->kitgview ) );
550 toolkitgroupview_set_mainw( mainw->kitgview, mainw );
551 gtk_menu_set_accel_group(
552 GTK_MENU( mainw->kitgview->menu ),
553 iwnd->accel_group );
554
555 mainw->kitg = ws->kitg;
556 }
557 }
558
559 return( FALSE );
560 }
561
562 static void
mainw_refresh(Mainw * mainw)563 mainw_refresh( Mainw *mainw )
564 {
565 IM_FREEF( g_source_remove, mainw->refresh_timeout );
566
567 mainw->refresh_timeout = g_timeout_add( 100,
568 (GSourceFunc) mainw_refresh_timeout_cb, mainw );
569 }
570
571 static void
mainw_duplicate_action_cb(GtkAction * action,Mainw * mainw)572 mainw_duplicate_action_cb( GtkAction *action, Mainw *mainw )
573 {
574 Workspacegroup *new_wsg;
575 Mainw *new_mainw;
576
577 progress_begin();
578
579 if( !(new_wsg = workspacegroup_duplicate( mainw->wsg )) ) {
580 progress_end();
581 iwindow_alert( GTK_WIDGET( mainw ), GTK_MESSAGE_ERROR );
582 return;
583 }
584
585 new_mainw = mainw_new( new_wsg );
586 gtk_widget_show( GTK_WIDGET( new_mainw ) );
587
588 symbol_recalculate_all();
589
590 progress_end();
591 }
592
593 static void
mainw_save_action_cb(GtkAction * action,Mainw * mainw)594 mainw_save_action_cb( GtkAction *action, Mainw *mainw )
595 {
596 workspacegroup_set_save_type( mainw->wsg, WORKSPACEGROUP_SAVE_ALL );
597 filemodel_inter_save( IWINDOW( mainw ), FILEMODEL( mainw->wsg ) );
598 }
599
600 static void
mainw_save_as_action_cb(GtkAction * action,Mainw * mainw)601 mainw_save_as_action_cb( GtkAction *action, Mainw *mainw )
602 {
603 workspacegroup_set_save_type( mainw->wsg, WORKSPACEGROUP_SAVE_ALL );
604 filemodel_inter_saveas( IWINDOW( mainw ), FILEMODEL( mainw->wsg ) );
605 }
606
607 /* Event in the "space free" display ... toggle mode on left click.
608 */
609 static gint
mainw_space_free_event(GtkWidget * widget,GdkEvent * ev,Mainw * mainw)610 mainw_space_free_event( GtkWidget *widget, GdkEvent *ev, Mainw *mainw )
611 {
612 if( ev->type == GDK_BUTTON_RELEASE ) {
613 mainw->free_type = !mainw->free_type;
614 mainw_free_update( mainw );
615 }
616
617 return( FALSE );
618 }
619
620 /* Count number and sizes of all image objects.
621 */
622
623 static void *
mainw_count_images(VipsObject * object,int * n)624 mainw_count_images( VipsObject *object, int *n )
625 {
626 if( VIPS_IS_IMAGE( object ) )
627 *n += 1;
628
629 return( NULL );
630 }
631
632 static void *
mainw_size_images(VipsObject * object,size_t * size)633 mainw_size_images( VipsObject *object, size_t *size )
634 {
635 if( VIPS_IS_IMAGE( object ) )
636 *size += VIPS_IMAGE_SIZEOF_IMAGE( VIPS_IMAGE( object ) );
637
638 return( NULL );
639 }
640
641 static void
mainw_space_free_tooltip_generate(GtkWidget * widget,VipsBuf * buf,Mainw * mainw)642 mainw_space_free_tooltip_generate( GtkWidget *widget, VipsBuf *buf,
643 Mainw *mainw )
644 {
645 Heap *heap = reduce_context->heap;
646
647 size_t size;
648 int n;
649
650 mainw_find_disc( buf );
651 /* Expands to (eg.) "14GB free in /pics/tmp" */
652 vips_buf_appendf( buf, _( " in \"%s\"" ), PATH_TMP );
653 vips_buf_appends( buf, ", " );
654
655 vips_buf_appendf( buf,
656 _( "%d cells in heap, %d cells free, %d cells maximum" ),
657 heap->ncells, heap->nfree, heap->max_fn( heap ) );
658 vips_buf_appends( buf, ", " );
659
660 if( mainw->wsg ) {
661 vips_buf_appendf( buf, _( "%d objects in workspace" ),
662 workspacegroup_get_n_objects( mainw->wsg ) );
663 vips_buf_appends( buf, ", " );
664 }
665
666 vips_buf_appendf( buf, _( "%d vips calls cached" ),
667 cache_history_size );
668 vips_buf_appends( buf, ", " );
669
670 vips_buf_appendf( buf, _( "using %d threads" ), im_concurrency_get() );
671 vips_buf_appends( buf, ", " );
672
673 size = 0;
674 vips_object_map( (VipsSListMap2Fn) mainw_size_images, &size, NULL );
675 n = 0;
676 vips_object_map( (VipsSListMap2Fn) mainw_count_images, &n, NULL );
677
678 vips_buf_append_size( buf, size );
679 vips_buf_appendf( buf, _( " in %d images" ), n );
680 }
681
682 static void
mainw_free_changed_cb(gpointer * dummy,Mainw * mainw)683 mainw_free_changed_cb( gpointer *dummy, Mainw *mainw )
684 {
685 mainw_free_update( mainw );
686 mainw_status_update( mainw );
687 }
688
689 /* Go to home page.
690 */
691 void
mainw_homepage_action_cb(GtkAction * action,iWindow * iwnd)692 mainw_homepage_action_cb( GtkAction *action, iWindow *iwnd )
693 {
694 box_url( GTK_WIDGET( iwnd ), VIPS_HOMEPAGE );
695 }
696
697 /* About... box.
698 */
699 void
mainw_about_action_cb(GtkAction * action,iWindow * iwnd)700 mainw_about_action_cb( GtkAction *action, iWindow *iwnd )
701 {
702 box_about( GTK_WIDGET( iwnd ) );
703 }
704
705 /* User's guide.
706 */
707 void
mainw_guide_action_cb(GtkAction * action,iWindow * iwnd)708 mainw_guide_action_cb( GtkAction *action, iWindow *iwnd )
709 {
710 box_url( GTK_WIDGET( iwnd ), "file://" NIP_DOCPATH "/nipguide.html" );
711 }
712
713 static void
mainw_selected_duplicate_action_cb(GtkAction * action,Mainw * mainw)714 mainw_selected_duplicate_action_cb( GtkAction *action, Mainw *mainw )
715 {
716 Workspace *ws;
717
718 progress_begin();
719 if( (ws = mainw_get_workspace( mainw )) &&
720 !workspace_selected_duplicate( ws ) )
721 iwindow_alert( GTK_WIDGET( mainw ), GTK_MESSAGE_ERROR );
722 progress_end();
723 }
724
725 /* Ungroup the selected object(s), or the bottom object.
726 */
727 static void
mainw_ungroup_action_cb(GtkAction * action,Mainw * mainw)728 mainw_ungroup_action_cb( GtkAction *action, Mainw *mainw )
729 {
730 Workspace *ws;
731
732 progress_begin();
733 if( (ws = mainw_get_workspace( mainw )) &&
734 !workspace_selected_ungroup( ws ) )
735 iwindow_alert( GTK_WIDGET( mainw ), GTK_MESSAGE_ERROR );
736 progress_end();
737 }
738
739 /* Group the selected object(s).
740 */
741 void
mainw_group_action_cb(GtkAction * action,Mainw * mainw)742 mainw_group_action_cb( GtkAction *action, Mainw *mainw )
743 {
744 Workspace *ws;
745
746 if( (ws = mainw_get_workspace( mainw )) )
747 workspace_selected_group( ws );
748 }
749
750 /* Select all objects.
751 */
752 static void
mainw_select_all_action_cb(GtkAction * action,Mainw * mainw)753 mainw_select_all_action_cb( GtkAction *action, Mainw *mainw )
754 {
755 Workspace *ws;
756
757 if( (ws = mainw_get_workspace( mainw )) )
758 workspace_select_all( ws );
759 }
760
761 static void
mainw_find_action_cb(GtkAction * action,Mainw * mainw)762 mainw_find_action_cb( GtkAction *action, Mainw *mainw )
763 {
764 error_top( _( "Not implemented." ) );
765 error_sub( _( "Find in workspace not implemented yet." ) );
766 iwindow_alert( GTK_WIDGET( mainw ), GTK_MESSAGE_INFO );
767 }
768
769 static void
mainw_find_again_action_cb(GtkAction * action,Mainw * mainw)770 mainw_find_again_action_cb( GtkAction *action, Mainw *mainw )
771 {
772 error_top( _( "Not implemented." ) );
773 error_sub( _( "Find again in workspace not implemented yet." ) );
774 iwindow_alert( GTK_WIDGET( mainw ), GTK_MESSAGE_INFO );
775 }
776
777 void
mainw_next_error_action_cb(GtkAction * action,Mainw * mainw)778 mainw_next_error_action_cb( GtkAction *action, Mainw *mainw )
779 {
780 Workspace *first_ws;
781 Workspace *ws;
782
783 if( !(first_ws = mainw_get_workspace( mainw )) )
784 return;
785
786 do {
787 ws = mainw_get_workspace( mainw );
788
789 if( workspace_next_error( ws ) )
790 return;
791
792 ws = mainw_next_workspace( mainw );
793 } while( ws != first_ws );
794
795 error_top( _( "No errors in workspace." ) );
796 error_sub( "%s", _( "There are no errors (that I can see) "
797 "in this workspace." ) );
798 iwindow_alert( GTK_WIDGET( mainw ), GTK_MESSAGE_INFO );
799 }
800
801 static void
mainw_force_calc_action_cb(GtkAction * action,Mainw * mainw)802 mainw_force_calc_action_cb( GtkAction *action, Mainw *mainw )
803 {
804 Workspace *ws;
805
806 if( (ws = mainw_get_workspace( mainw )) &&
807 workspace_selected_any( ws ) ) {
808 if( !workspace_selected_recalc( ws ) )
809 iwindow_alert( GTK_WIDGET( mainw ), GTK_MESSAGE_ERROR );
810 }
811 else
812 symbol_recalculate_all_force( TRUE );
813 }
814
815 Workspacegroup *
mainw_open_workspace(Workspaceroot * wsr,const char * filename)816 mainw_open_workspace( Workspaceroot *wsr, const char *filename )
817 {
818 Workspacegroup *wsg;
819 Mainw *mainw;
820
821 if( !(wsg = workspacegroup_new_from_file( wsr, filename, filename )) )
822 return( NULL );
823 mainw = mainw_new( wsg );
824 gtk_widget_show( GTK_WIDGET( mainw ) );
825
826 return( wsg );
827 }
828
829 /* Track these during a load.
830 */
831 typedef struct {
832 Mainw *mainw;
833 VipsBuf *buf;
834 int nitems;
835 } MainwLoad;
836
837 /* Try to open a file. Workspace files we load immediately, other ones we
838 * add the load to a buffer.
839 */
840 static void *
mainw_open_fn(Filesel * filesel,const char * filename,MainwLoad * load)841 mainw_open_fn( Filesel *filesel, const char *filename, MainwLoad *load )
842 {
843 Workspaceroot *wsr = load->mainw->wsg->wsr;
844
845 if( is_file_type( &filesel_wfile_type, filename ) ) {
846 if( !mainw_open_workspace( wsr, filename ) )
847 return( filesel );
848 mainw_recent_add( &mainw_recent_workspace, filename );
849 }
850 else {
851 if( load->nitems )
852 vips_buf_appends( load->buf, ", " );
853 if( !workspace_load_file_buf( load->buf, filename ) )
854 return( filesel );
855 mainw_recent_add( &mainw_recent_image, filename );
856 load->nitems += 1;
857 }
858
859 return( NULL );
860 }
861
862 /* Callback from load browser.
863 */
864 static void
mainw_open_done_cb(iWindow * iwnd,void * client,iWindowNotifyFn nfn,void * sys)865 mainw_open_done_cb( iWindow *iwnd, void *client,
866 iWindowNotifyFn nfn, void *sys )
867 {
868 Mainw *mainw = MAINW( client );
869 Filesel *filesel = FILESEL( iwnd );
870 char txt[MAX_STRSIZE];
871 VipsBuf buf = VIPS_BUF_STATIC( txt );
872 MainwLoad load;
873 Workspace *ws;
874
875 load.mainw = mainw;
876 load.buf = &buf;
877 load.nitems = 0;
878
879 if( filesel_map_filename_multi( filesel,
880 (FileselMapFn) mainw_open_fn, &load, NULL ) ) {
881 nfn( sys, IWINDOW_ERROR );
882 return;
883 }
884
885 /* Some actual files (image, matrix) were selected. Load into
886 * the current workspace.
887 */
888 if( load.nitems &&
889 (ws = mainw_get_workspace( mainw )) ) {
890 char txt2[MAX_STRSIZE];
891 VipsBuf buf2 = VIPS_BUF_STATIC( txt2 );
892
893 if( load.nitems > 1 )
894 vips_buf_appendf( &buf2, "Group [%s]",
895 vips_buf_all( &buf ) );
896 else
897 vips_buf_appends( &buf2, vips_buf_all( &buf ) );
898
899 if( !workspace_add_def_recalc( ws, vips_buf_all( &buf2 ) ) ) {
900 error_top( _( "Load failed." ) );
901 error_sub( _( "Unable to execute:\n %s" ),
902 vips_buf_all( &buf2 ) );
903 nfn( sys, IWINDOW_ERROR );
904 return;
905 }
906 }
907
908 /* Wses will need a recalc.
909 */
910 symbol_recalculate_all();
911
912 /* If we had an empty wsg, perhaps we've just started up,
913 * kill it.
914 */
915 if( workspacegroup_is_empty( mainw->wsg ) ) {
916 filemodel_set_modified( FILEMODEL( mainw->wsg ), FALSE );
917 iwindow_kill( IWINDOW( mainw ) );
918 }
919
920 nfn( sys, IWINDOW_YES );
921 }
922
923 /* Show an open file dialog ... any type, but default to one of the image
924 * ones.
925 */
926 static void
mainw_open(Mainw * mainw)927 mainw_open( Mainw *mainw )
928 {
929 GtkWidget *filesel = filesel_new();
930
931 iwindow_set_title( IWINDOW( filesel ), _( "Open File" ) );
932 filesel_set_flags( FILESEL( filesel ), TRUE, FALSE );
933 filesel_set_filetype( FILESEL( filesel ),
934 filesel_type_mainw, IMAGE_FILE_TYPE );
935 filesel_set_filetype_pref( FILESEL( filesel ), "IMAGE_FILE_TYPE" );
936 iwindow_set_parent( IWINDOW( filesel ), GTK_WIDGET( mainw ) );
937 filesel_set_done( FILESEL( filesel ),
938 mainw_open_done_cb, mainw );
939 filesel_set_multi( FILESEL( filesel ), TRUE );
940 iwindow_build( IWINDOW( filesel ) );
941
942 gtk_widget_show( GTK_WIDGET( filesel ) );
943 }
944
945 void
mainw_open_action_cb(GtkAction * action,Mainw * mainw)946 mainw_open_action_cb( GtkAction *action, Mainw *mainw )
947 {
948 mainw_open( mainw );
949 }
950
951 /* Open one of the example workspaces ... just a shortcut.
952 */
953 static void
mainw_open_examples(Mainw * mainw)954 mainw_open_examples( Mainw *mainw )
955 {
956 GtkWidget *filesel = filesel_new();
957
958 iwindow_set_title( IWINDOW( filesel ), _( "Open File" ) );
959 filesel_set_flags( FILESEL( filesel ), TRUE, FALSE );
960 filesel_set_filetype( FILESEL( filesel ),
961 filesel_type_workspace, 0 );
962 iwindow_set_parent( IWINDOW( filesel ), GTK_WIDGET( mainw ) );
963 filesel_set_done( FILESEL( filesel ),
964 mainw_open_done_cb, mainw );
965 filesel_set_multi( FILESEL( filesel ), TRUE );
966 iwindow_build( IWINDOW( filesel ) );
967 filesel_set_filename( FILESEL( filesel ),
968 "$VIPSHOME" G_DIR_SEPARATOR_S "share" G_DIR_SEPARATOR_S
969 PACKAGE G_DIR_SEPARATOR_S "data" G_DIR_SEPARATOR_S
970 "examples" G_DIR_SEPARATOR_S "1_point_mosaic" );
971
972 /* Reset the filetype ... setting the filename will have changed it to
973 * 'all', since there's no suffix.
974 */
975 filesel_set_filetype( FILESEL( filesel ),
976 filesel_type_workspace, 0 );
977
978 gtk_widget_show( GTK_WIDGET( filesel ) );
979 }
980
981 static void
mainw_open_examples_action_cb(GtkAction * action,Mainw * mainw)982 mainw_open_examples_action_cb( GtkAction *action, Mainw *mainw )
983 {
984 mainw_open_examples( mainw );
985 }
986
987 static gboolean
mainw_recent_open(Mainw * mainw,const char * filename)988 mainw_recent_open( Mainw *mainw, const char *filename )
989 {
990 Workspacegroup *wsg = mainw->wsg;
991
992 if( is_file_type( &filesel_wfile_type, filename ) ) {
993 if( !mainw_open_workspace( wsg->wsr, filename ) )
994 return( FALSE );
995
996 /* If we had an empty wsg, perhaps we've just started up,
997 * kill it.
998 */
999 if( workspacegroup_is_empty( wsg ) ) {
1000 filemodel_set_modified( FILEMODEL( wsg ), FALSE );
1001 iwindow_kill( IWINDOW( mainw ) );
1002 }
1003 }
1004 else {
1005 Workspace *ws;
1006
1007 if( (ws = mainw_get_workspace( mainw )) &&
1008 !workspace_load_file( ws, filename ) )
1009 return( FALSE );
1010 }
1011
1012 return( TRUE );
1013 }
1014
1015 static void
mainw_recent_open_cb(GtkWidget * widget,const char * filename)1016 mainw_recent_open_cb( GtkWidget *widget, const char *filename )
1017 {
1018 Mainw *mainw = MAINW( iwindow_get_root( widget ) );
1019
1020 progress_begin();
1021 if( !mainw_recent_open( mainw, filename ) ) {
1022 iwindow_alert( GTK_WIDGET( mainw ), GTK_MESSAGE_ERROR );
1023 progress_end();
1024 return;
1025 }
1026 progress_end();
1027
1028 symbol_recalculate_all();
1029 }
1030
1031 static void
mainw_recent_build(GtkWidget * menu,GSList * recent)1032 mainw_recent_build( GtkWidget *menu, GSList *recent )
1033 {
1034 GSList *p;
1035
1036 for( p = recent; p; p = p->next ) {
1037 const char *filename = (const char *) p->data;
1038 GtkWidget *item;
1039 char txt[80];
1040 VipsBuf buf = VIPS_BUF_STATIC( txt );
1041 char *utf8;
1042
1043 vips_buf_appendf( &buf, " %s", im_skip_dir( filename ) );
1044 utf8 = f2utf8( vips_buf_all( &buf ) );
1045 item = gtk_menu_item_new_with_label( utf8 );
1046 g_free( utf8 );
1047 utf8 = f2utf8( filename );
1048 set_tooltip( item, "%s", utf8 );
1049 g_free( utf8 );
1050 gtk_menu_append( GTK_MENU( menu ), item );
1051 gtk_widget_show( item );
1052 gtk_signal_connect( GTK_OBJECT( item ), "activate",
1053 GTK_SIGNAL_FUNC( mainw_recent_open_cb ),
1054 (char *) filename );
1055 }
1056 }
1057
1058 static void
mainw_recent_clear_cb(GtkWidget * widget,const char * filename)1059 mainw_recent_clear_cb( GtkWidget *widget, const char *filename )
1060 {
1061 IM_FREEF( recent_free, mainw_recent_workspace );
1062 IM_FREEF( recent_free, mainw_recent_image );
1063 IM_FREEF( recent_free, mainw_recent_matrix );
1064
1065 /* Need to remove files too to prevent merge on quit.
1066 */
1067 (void) unlinkf( "%s" G_DIR_SEPARATOR_S "%s",
1068 get_savedir(), RECENT_WORKSPACE );
1069 (void) unlinkf( "%s" G_DIR_SEPARATOR_S "%s",
1070 get_savedir(), RECENT_IMAGE );
1071 (void) unlinkf( "%s" G_DIR_SEPARATOR_S "%s",
1072 get_savedir(), RECENT_MATRIX );
1073 }
1074
1075 static void
mainw_recent_map_cb(GtkWidget * widget,Mainw * mainw)1076 mainw_recent_map_cb( GtkWidget *widget, Mainw *mainw )
1077 {
1078 GtkWidget *menu = mainw->recent_menu;
1079 GtkWidget *item;
1080
1081 gtk_container_foreach( GTK_CONTAINER( menu ),
1082 (GtkCallback) gtk_widget_destroy, NULL );
1083
1084 if( mainw_recent_image ) {
1085 item = gtk_menu_item_new_with_label( _( "Recent Images" ) );
1086 gtk_menu_append( GTK_MENU( menu ), item );
1087 gtk_widget_show( item );
1088 gtk_widget_set_sensitive( item, FALSE );
1089 mainw_recent_build( menu, mainw_recent_image );
1090 }
1091
1092 if( mainw_recent_workspace ) {
1093 item = gtk_menu_item_new_with_label( _( "Recent Workspaces" ) );
1094 gtk_menu_append( GTK_MENU( menu ), item );
1095 gtk_widget_show( item );
1096 gtk_widget_set_sensitive( item, FALSE );
1097 mainw_recent_build( menu, mainw_recent_workspace );
1098 }
1099
1100 if( mainw_recent_matrix ) {
1101 item = gtk_menu_item_new_with_label( _( "Recent Matricies" ) );
1102 gtk_menu_append( GTK_MENU( menu ), item );
1103 gtk_widget_show( item );
1104 gtk_widget_set_sensitive( item, FALSE );
1105 mainw_recent_build( menu, mainw_recent_matrix );
1106 }
1107
1108 if( !mainw_recent_workspace && !mainw_recent_image &&
1109 !mainw_recent_matrix ) {
1110 item = gtk_menu_item_new_with_label( _( "No recent items" ) );
1111 gtk_menu_append( GTK_MENU( menu ), item );
1112 gtk_widget_show( item );
1113 gtk_widget_set_sensitive( item, FALSE );
1114 }
1115 else {
1116 item = gtk_menu_item_new_with_label( _( "Clear Recent Menu" ) );
1117 gtk_menu_append( GTK_MENU( menu ), item );
1118 gtk_widget_show( item );
1119 gtk_signal_connect( GTK_OBJECT( item ), "activate",
1120 GTK_SIGNAL_FUNC( mainw_recent_clear_cb ), NULL );
1121 }
1122 }
1123
1124 /* Merge a .ws into this wsg.
1125 */
1126 static void *
mainw_workspace_merge_fn(Filesel * filesel,const char * filename,void * a,void * b)1127 mainw_workspace_merge_fn( Filesel *filesel,
1128 const char *filename, void *a, void *b )
1129 {
1130 Mainw *mainw = MAINW( a );
1131
1132 if( !workspacegroup_merge_workspaces( mainw->wsg, filename ) )
1133 return( filesel );
1134
1135 /* Process some events to make sure we rethink the layout and
1136 * are able to get the append-at-RHS offsets.
1137 */
1138 process_events();
1139
1140 symbol_recalculate_all();
1141 mainw_recent_add( &mainw_recent_workspace, filename );
1142
1143 return( NULL );
1144 }
1145
1146 /* Callback from load browser.
1147 */
1148 static void
mainw_workspace_merge_done_cb(iWindow * iwnd,void * client,iWindowNotifyFn nfn,void * sys)1149 mainw_workspace_merge_done_cb( iWindow *iwnd,
1150 void *client, iWindowNotifyFn nfn, void *sys )
1151 {
1152 Filesel *filesel = FILESEL( iwnd );
1153 Mainw *mainw = MAINW( client );
1154
1155 if( filesel_map_filename_multi( filesel,
1156 mainw_workspace_merge_fn, mainw, NULL ) ) {
1157 symbol_recalculate_all();
1158 nfn( sys, IWINDOW_ERROR );
1159 return;
1160 }
1161
1162 symbol_recalculate_all();
1163
1164 nfn( sys, IWINDOW_YES );
1165 }
1166
1167 /* Merge ws file into current ws.
1168 */
1169 void
mainw_workspace_merge(Mainw * mainw)1170 mainw_workspace_merge( Mainw *mainw )
1171 {
1172 GtkWidget *filesel = filesel_new();
1173
1174 iwindow_set_title( IWINDOW( filesel ),
1175 _( "Merge Workspace from File" ) );
1176 filesel_set_flags( FILESEL( filesel ), FALSE, FALSE );
1177 filesel_set_filetype( FILESEL( filesel ), filesel_type_workspace, 0 );
1178 iwindow_set_parent( IWINDOW( filesel ), GTK_WIDGET( mainw ) );
1179 filesel_set_done( FILESEL( filesel ),
1180 mainw_workspace_merge_done_cb, mainw );
1181 filesel_set_multi( FILESEL( filesel ), TRUE );
1182 iwindow_build( IWINDOW( filesel ) );
1183
1184 gtk_widget_show( GTK_WIDGET( filesel ) );
1185 }
1186
1187 void
mainw_workspace_merge_action_cb(GtkAction * action,Mainw * mainw)1188 mainw_workspace_merge_action_cb( GtkAction *action, Mainw *mainw )
1189 {
1190 mainw_workspace_merge( mainw );
1191 }
1192
1193 /* Load a workspace, called from a yesno dialog.
1194 */
1195 static void
mainw_auto_recover_cb(iWindow * iwnd,void * client,iWindowNotifyFn nfn,void * sys)1196 mainw_auto_recover_cb( iWindow *iwnd,
1197 void *client, iWindowNotifyFn nfn, void *sys )
1198 {
1199 char *filename = (char *) client;
1200
1201 Workspacegroup *new_wsg;
1202 Mainw *new_mainw;
1203
1204 progress_begin();
1205
1206 if( !(new_wsg = workspacegroup_new_from_file( main_workspaceroot,
1207 filename, filename )) ) {
1208 progress_end();
1209 nfn( sys, IWINDOW_ERROR );
1210 return;
1211 }
1212
1213 filemodel_set_filename( FILEMODEL( new_wsg ), NULL );
1214
1215 new_mainw = mainw_new( new_wsg );
1216 gtk_widget_show( GTK_WIDGET( new_mainw ) );
1217
1218 symbol_recalculate_all();
1219
1220 progress_end();
1221
1222 nfn( sys, IWINDOW_YES );
1223 }
1224
1225 /* Auto recover.
1226 */
1227 static void
mainw_recover_action_cb(GtkAction * action,Mainw * mainw)1228 mainw_recover_action_cb( GtkAction *action, Mainw *mainw )
1229 {
1230 char *filename;
1231
1232 if( !(filename = workspacegroup_autosave_recover()) ) {
1233 if( !AUTO_WS_SAVE ) {
1234 error_top( _( "No backup workspaces found." ) );
1235 error_sub( "%s",
1236 _( "You need to enable \"Auto workspace "
1237 "save\" in Preferences "
1238 "before automatic recovery works." ) );
1239 }
1240 else {
1241 error_top( _( "No backup workspaces found." ) );
1242 error_sub( _( "No suitable workspace save files found "
1243 "in \"%s\"" ), PATH_TMP );
1244 }
1245
1246 iwindow_alert( GTK_WIDGET( mainw ), GTK_MESSAGE_INFO );
1247 return;
1248 }
1249
1250 /* Tricksy ... free str with notify callack from yesno.
1251 */
1252
1253 box_yesno( GTK_WIDGET( mainw ),
1254 mainw_auto_recover_cb, iwindow_true_cb, filename,
1255 (iWindowNotifyFn) im_free, filename,
1256 GTK_STOCK_OPEN,
1257 _( "Open workspace backup?" ),
1258 _( "Found workspace backup:\n\n\t%s\n\n"
1259 "Do you want to recover this workspace?" ),
1260 filename );
1261 }
1262
1263 /* Callback from make new column.
1264 */
1265 void
mainw_column_new_action_cb(GtkAction * action,Mainw * mainw)1266 mainw_column_new_action_cb( GtkAction *action, Mainw *mainw )
1267 {
1268 Workspace *ws;
1269
1270 if( (ws = mainw_get_workspace( mainw )) )
1271 (void) workspace_column_new( ws );
1272 }
1273
1274 /* Done button hit.
1275 */
1276 static void
mainw_column_new_cb(iWindow * iwnd,void * client,iWindowNotifyFn nfn,void * sys)1277 mainw_column_new_cb( iWindow *iwnd, void *client,
1278 iWindowNotifyFn nfn, void *sys )
1279 {
1280 Mainw *mainw = MAINW( client );
1281 Stringset *ss = STRINGSET( iwnd );
1282 StringsetChild *name = stringset_child_get( ss, _( "Name" ) );
1283 StringsetChild *caption = stringset_child_get( ss, _( "Caption" ) );
1284
1285 Workspace *ws;
1286 Column *col;
1287
1288 char name_text[1024];
1289 char caption_text[1024];
1290
1291 if( !(ws = mainw_get_workspace( mainw )) ) {
1292 nfn( sys, IWINDOW_YES );
1293 return;
1294 }
1295
1296 if( !get_geditable_name( name->entry, name_text, 1024 ) ||
1297 !get_geditable_string( caption->entry, caption_text, 1024 ) ) {
1298 nfn( sys, IWINDOW_ERROR );
1299 return;
1300 }
1301
1302 if( !(col = column_new( ws, name_text )) ) {
1303 nfn( sys, IWINDOW_ERROR );
1304 return;
1305 }
1306
1307 if( strcmp( caption_text, "" ) != 0 )
1308 iobject_set( IOBJECT( col ), NULL, caption_text );
1309
1310 workspace_column_select( ws, col );
1311
1312 column_scrollto( col, MODEL_SCROLL_TOP );
1313
1314 nfn( sys, IWINDOW_YES );
1315 }
1316
1317 /* Make a new column with a specified name.
1318 */
1319 static void
mainw_column_new_named_action_cb(GtkAction * action,Mainw * mainw)1320 mainw_column_new_named_action_cb( GtkAction *action, Mainw *mainw )
1321 {
1322 GtkWidget *ss = stringset_new();
1323 char new_name[MAX_STRSIZE];
1324 Workspace *ws;
1325
1326 if( !(ws = mainw_get_workspace( mainw )) )
1327 return;
1328
1329 workspace_column_name_new( ws, new_name );
1330
1331 stringset_child_new( STRINGSET( ss ),
1332 _( "Name" ), new_name, _( "Set column name here" ) );
1333 stringset_child_new( STRINGSET( ss ),
1334 _( "Caption" ), "", _( "Set column caption here" ) );
1335
1336 iwindow_set_title( IWINDOW( ss ), _( "New Column" ) );
1337 idialog_set_callbacks( IDIALOG( ss ),
1338 iwindow_true_cb, NULL, NULL, mainw );
1339 idialog_add_ok( IDIALOG( ss ),
1340 mainw_column_new_cb, _( "Create Column" ) );
1341 iwindow_set_parent( IWINDOW( ss ), GTK_WIDGET( mainw ) );
1342 iwindow_build( IWINDOW( ss ) );
1343
1344 gtk_widget_show( ss );
1345 }
1346
1347 /* Callback from program.
1348 */
1349 static void
mainw_program_new_action_cb(GtkAction * action,Mainw * mainw)1350 mainw_program_new_action_cb( GtkAction *action, Mainw *mainw )
1351 {
1352 Workspace *ws;
1353
1354 if( (ws = mainw_get_workspace( mainw )) ) {
1355 Program *program;
1356
1357 program = program_new( ws->kitg );
1358 gtk_widget_show( GTK_WIDGET( program ) );
1359 }
1360 }
1361
1362 static void
mainw_workspace_new_action_cb(GtkAction * action,Mainw * mainw)1363 mainw_workspace_new_action_cb( GtkAction *action, Mainw *mainw )
1364 {
1365 workspace_new_blank( mainw->wsg );
1366 }
1367
1368 /* New workbook.
1369 */
1370 static void
mainw_workbook_new_action_cb(GtkAction * action,Mainw * mainw)1371 mainw_workbook_new_action_cb( GtkAction *action, Mainw *mainw )
1372 {
1373 Mainw *new_mainw;
1374 Workspacegroup *new_wsg;
1375 char name[256];
1376
1377 workspaceroot_name_new( mainw->wsg->wsr, name );
1378 new_wsg = workspacegroup_new_blank( mainw->wsg->wsr, name );
1379 new_mainw = mainw_new( new_wsg );
1380 gtk_widget_show( GTK_WIDGET( new_mainw ) );
1381 }
1382
1383 /* Callback from auto-recalc toggle.
1384 */
1385 static void
mainw_autorecalc_action_cb(GtkToggleAction * action,Mainw * mainw)1386 mainw_autorecalc_action_cb( GtkToggleAction *action, Mainw *mainw )
1387 {
1388 GSList *i;
1389
1390 mainw_auto_recalc = gtk_toggle_action_get_active( action );
1391
1392 /* Yuk! We have to ask all mainw to refresh by hand, since we're not
1393 * using the prefs system for auto_recalc for reasons noted at top.
1394 */
1395 for( i = mainw_all; i; i = i->next )
1396 mainw_refresh( MAINW( i->data ) );
1397
1398 if( mainw_auto_recalc )
1399 symbol_recalculate_all();
1400 }
1401
1402 /* Callback from lock toggle.
1403 */
1404 static void
mainw_lock_action_cb(GtkToggleAction * action,Mainw * mainw)1405 mainw_lock_action_cb( GtkToggleAction *action, Mainw *mainw )
1406 {
1407 Workspace *ws;
1408
1409 if( (ws = mainw_get_workspace( mainw )) )
1410 workspace_set_locked( ws,
1411 gtk_toggle_action_get_active( action ) );
1412 }
1413
1414 /* Callback from show toolbar toggle.
1415 */
1416 static void
mainw_toolbar_action_cb(GtkToggleAction * action,Mainw * mainw)1417 mainw_toolbar_action_cb( GtkToggleAction *action, Mainw *mainw )
1418 {
1419 mainw->toolbar_visible = gtk_toggle_action_get_active( action );
1420 prefs_set( "MAINW_TOOLBAR",
1421 "%s", bool_to_char( mainw->toolbar_visible ) );
1422 mainw_refresh( mainw );
1423 }
1424
1425 /* Callback from show statusbar toggle.
1426 */
1427 static void
mainw_statusbar_action_cb(GtkToggleAction * action,Mainw * mainw)1428 mainw_statusbar_action_cb( GtkToggleAction *action, Mainw *mainw )
1429 {
1430 mainw->statusbar_visible = gtk_toggle_action_get_active( action );
1431 prefs_set( "MAINW_STATUSBAR",
1432 "%s", bool_to_char( mainw->statusbar_visible ) );
1433 mainw_refresh( mainw );
1434 }
1435
1436 /* Expose/hide the toolkit browser.
1437 */
1438 static void
mainw_toolkitbrowser_action_cb(GtkToggleAction * action,Mainw * mainw)1439 mainw_toolkitbrowser_action_cb( GtkToggleAction *action, Mainw *mainw )
1440 {
1441 Workspace *ws;
1442
1443 if( (ws = mainw_get_workspace( mainw )) ) {
1444 ws->rpane_open = gtk_toggle_action_get_active( action );
1445 iobject_changed( IOBJECT( ws ) );
1446 }
1447 }
1448
1449 /* Expose/hide the workspace defs.
1450 */
1451 static void
mainw_tabdefs_action_cb(GtkToggleAction * action,Mainw * mainw)1452 mainw_tabdefs_action_cb( GtkToggleAction *action, Mainw *mainw )
1453 {
1454 Workspace *ws;
1455
1456 if( (ws = mainw_get_workspace( mainw )) ) {
1457 ws->lpane_open = gtk_toggle_action_get_active( action );
1458 iobject_changed( IOBJECT( ws ) );
1459 }
1460 }
1461
1462 /* Remove selected items.
1463 */
1464 static void
mainw_selected_remove_action_cb(GtkAction * action,Mainw * mainw)1465 mainw_selected_remove_action_cb( GtkAction *action, Mainw *mainw )
1466 {
1467 Workspace *ws;
1468
1469 if( (ws = mainw_get_workspace( mainw )) )
1470 workspace_selected_remove_yesno( ws, GTK_WIDGET( mainw ) );
1471 }
1472
1473 void
mainw_revert_ok_cb(iWindow * iwnd,void * client,iWindowNotifyFn nfn,void * sys)1474 mainw_revert_ok_cb( iWindow *iwnd, void *client,
1475 iWindowNotifyFn nfn, void *sys )
1476 {
1477 Prefs *prefs = PREFS( client );
1478 Workspacegroup *wsg = workspace_get_workspacegroup( prefs->ws );
1479
1480 if( FILEMODEL( wsg )->filename ) {
1481 (void) unlinkf( "%s", FILEMODEL( wsg )->filename );
1482 main_reload();
1483 symbol_recalculate_all();
1484 }
1485
1486 nfn( sys, IWINDOW_YES );
1487 }
1488
1489 void
mainw_revert_cb(iWindow * iwnd,void * client,iWindowNotifyFn nfn,void * sys)1490 mainw_revert_cb( iWindow *iwnd, void *client, iWindowNotifyFn nfn, void *sys )
1491 {
1492 Prefs *prefs = PREFS( client );
1493
1494 box_yesno( GTK_WIDGET( iwnd ),
1495 mainw_revert_ok_cb, iwindow_true_cb, prefs,
1496 nfn, sys,
1497 _( "Revert to Defaults" ),
1498 _( "Revert to installation defaults?" ),
1499 _( "Would you like to reset all preferences to their factory "
1500 "settings? This will delete any changes you have ever made "
1501 "to your preferences and may take a few seconds." ) );
1502 }
1503
1504 static void
mainw_preferences_action_cb(GtkAction * action,Mainw * mainw)1505 mainw_preferences_action_cb( GtkAction *action, Mainw *mainw )
1506 {
1507 Prefs *prefs;
1508
1509 /* Can fail if there's no prefs ws, or an error on load.
1510 */
1511 if( !(prefs = prefs_new( NULL )) ) {
1512 iwindow_alert( GTK_WIDGET( mainw ), GTK_MESSAGE_ERROR );
1513 return;
1514 }
1515
1516 iwindow_set_title( IWINDOW( prefs ), _( "Preferences" ) );
1517 iwindow_set_parent( IWINDOW( prefs ), GTK_WIDGET( mainw ) );
1518 idialog_set_callbacks( IDIALOG( prefs ),
1519 NULL, NULL, NULL, prefs );
1520 idialog_add_ok( IDIALOG( prefs ),
1521 mainw_revert_cb, _( "Revert to Defaults ..." ) );
1522 idialog_add_ok( IDIALOG( prefs ), iwindow_true_cb, GTK_STOCK_CLOSE );
1523 iwindow_build( IWINDOW( prefs ) );
1524
1525 /* Just big enough to avoid a horizontal scrollbar on my machine.
1526
1527 FIXME ... Yuk! There must be a better way to do this!
1528 Maybe a setting in prefs to suppress the h scrollbar?
1529
1530 */
1531 gtk_window_set_default_size( GTK_WINDOW( prefs ), 780, 480 );
1532
1533 gtk_widget_show( GTK_WIDGET( prefs ) );
1534 }
1535
1536 /* Make a magic definition for the selected symbol.
1537
1538 FIXME .. paste this back when magic is reinstated
1539
1540 static void
1541 mainw_magic_cb( gpointer callback_data, guint callback_action,
1542 GtkWidget *widget )
1543 {
1544 Workspace *ws = main_workspaceroot->current;
1545 Row *row = workspace_selected_one( ws );
1546
1547 if( !row )
1548 box_alert( mainw,
1549 "Select a single object with left-click, "
1550 "select Magic Definition." );
1551 else if( !magic_sym( row->sym ) )
1552 iwindow_alert( GTK_WIDGET( mainw ), GTK_MESSAGE_ERROR );
1553 else
1554 workspace_deselect_all( ws );
1555 }
1556 */
1557
1558 #ifdef HAVE_LIBGVC
1559 static void
mainw_graph_action_cb(GtkAction * action,Mainw * mainw)1560 mainw_graph_action_cb( GtkAction *action, Mainw *mainw )
1561 {
1562 Workspace *ws;
1563
1564 if( (ws = mainw_get_workspace( mainw )) ) {
1565 Graphwindow *graphwindow;
1566
1567 graphwindow = graphwindow_new( ws, GTK_WIDGET( mainw ) );
1568 gtk_widget_show( GTK_WIDGET( graphwindow ) );
1569 }
1570 }
1571 #endif /*HAVE_LIBGVC*/
1572
1573 /* Set display mode.
1574 */
1575 static void
mainw_mode_action_cb(GtkRadioAction * action,GtkRadioAction * current,Mainw * mainw)1576 mainw_mode_action_cb( GtkRadioAction *action, GtkRadioAction *current,
1577 Mainw *mainw )
1578 {
1579 Workspace *ws;
1580
1581 if( (ws = mainw_get_workspace( mainw )) )
1582 workspace_set_mode( ws,
1583 gtk_radio_action_get_current_value( action ) );
1584 }
1585
1586 /* Our actions.
1587 */
1588 static GtkActionEntry mainw_actions[] = {
1589 /* Menu items.
1590 */
1591 { "RecentMenu", NULL, N_( "Open _Recent" ) },
1592 { "JumpToColumnMenu", NULL, N_( "Jump to _Column" ) },
1593 { "ToolkitsMenu", NULL, N_( "_Toolkits" ) },
1594
1595 /* Dummy action ... replaced at runtime.
1596 */
1597 { "Stub",
1598 NULL, "", NULL, "", NULL },
1599
1600 /* Actions.
1601 */
1602 { "NewColumn",
1603 GTK_STOCK_NEW, N_( "C_olumn" ), NULL,
1604 N_( "Create a new column" ),
1605 G_CALLBACK( mainw_column_new_action_cb ) },
1606
1607 { "NewColumnName",
1608 GTK_STOCK_NEW, N_( "C_olumn" ), NULL,
1609 N_( "Create a new column with a specified name" ),
1610 G_CALLBACK( mainw_column_new_named_action_cb ) },
1611
1612 { "NewTab",
1613 GTK_STOCK_NEW, N_( "_Tab" ), "<control>T",
1614 N_( "Create a new tab" ),
1615 G_CALLBACK( mainw_workspace_new_action_cb ) },
1616
1617 { "NewWorkspace",
1618 GTK_STOCK_NEW, N_( "_Workspace" ), NULL,
1619 N_( "Create a new workspace" ),
1620 G_CALLBACK( mainw_workbook_new_action_cb ) },
1621
1622 { "Open",
1623 GTK_STOCK_OPEN, N_( "_Open" ), NULL,
1624 N_( "Open a file" ),
1625 G_CALLBACK( mainw_open_action_cb ) },
1626
1627 { "OpenExamples",
1628 NULL, N_( "Open _Examples" ), NULL,
1629 N_( "Open example workspaces" ),
1630 G_CALLBACK( mainw_open_examples_action_cb ) },
1631
1632 { "DuplicateWorkspace",
1633 STOCK_DUPLICATE, N_( "_Duplicate Workspace" ), NULL,
1634 N_( "Duplicate workspace" ),
1635 G_CALLBACK( mainw_duplicate_action_cb ) },
1636
1637 { "Merge",
1638 NULL, N_( "_Merge Into Workspace" ), NULL,
1639 N_( "Merge workspace into this workspace" ),
1640 G_CALLBACK( mainw_workspace_merge_action_cb ) },
1641
1642 { "Save",
1643 GTK_STOCK_SAVE, N_( "_Save Workspace" ), NULL,
1644 N_( "Save workspace" ),
1645 G_CALLBACK( mainw_save_action_cb ) },
1646
1647 { "SaveAs",
1648 GTK_STOCK_SAVE_AS, N_( "_Save Workspace As" ), NULL,
1649 N_( "Save workspace as" ),
1650 G_CALLBACK( mainw_save_as_action_cb ) },
1651
1652 { "Recover",
1653 NULL, N_( "Search for Workspace _Backups" ), NULL,
1654 N_( "Load last automatically backed-up workspace" ),
1655 G_CALLBACK( mainw_recover_action_cb ) },
1656
1657 { "Delete",
1658 GTK_STOCK_DELETE, N_( "_Delete" ), "<control>BackSpace",
1659 N_( "Delete selected items" ),
1660 G_CALLBACK( mainw_selected_remove_action_cb ) },
1661
1662 { "SelectAll",
1663 NULL, N_( "Select _All" ), "<control>A",
1664 N_( "Select all items" ),
1665 G_CALLBACK( mainw_select_all_action_cb ) },
1666
1667 { "Duplicate",
1668 STOCK_DUPLICATE, N_( "D_uplicate Selected" ), "<control>U",
1669 N_( "Duplicate selected items" ),
1670 G_CALLBACK( mainw_selected_duplicate_action_cb ) },
1671
1672 { "Recalculate",
1673 NULL, N_( "_Recalculate" ), NULL,
1674 N_( "Recalculate selected items" ),
1675 G_CALLBACK( mainw_force_calc_action_cb ) },
1676
1677 { "Find",
1678 GTK_STOCK_FIND, N_( "_Find" ), NULL,
1679 N_( "Find in workspace" ),
1680 G_CALLBACK( mainw_find_action_cb ) },
1681
1682 { "FindNext",
1683 NULL, N_( "Find _Next" ), NULL,
1684 N_( "Find again in workspace" ),
1685 G_CALLBACK( mainw_find_again_action_cb ) },
1686
1687 { "NextError",
1688 STOCK_NEXT_ERROR, NULL, NULL,
1689 N_( "Jump to next error" ),
1690 G_CALLBACK( mainw_next_error_action_cb ) },
1691
1692 { "Group",
1693 NULL, N_( "_Group" ), NULL,
1694 N_( "Group selected items" ),
1695 G_CALLBACK( mainw_group_action_cb ) },
1696
1697 { "Ungroup",
1698 NULL, N_( "U_ngroup" ), NULL,
1699 N_( "Ungroup selected items" ),
1700 G_CALLBACK( mainw_ungroup_action_cb ) },
1701
1702 { "Preferences",
1703 GTK_STOCK_PREFERENCES, N_( "_Preferences" ), NULL,
1704 N_( "Edit preferences" ),
1705 G_CALLBACK( mainw_preferences_action_cb ) },
1706
1707 #ifdef HAVE_LIBGVC
1708 { "Graph",
1709 NULL, N_( "Workspace as Grap_h" ), NULL,
1710 N_( "Show a graph of workspace dependencies" ),
1711 G_CALLBACK( mainw_graph_action_cb ) },
1712 #endif /*HAVE_LIBGVC*/
1713
1714 { "EditToolkits",
1715 NULL, N_( "_Edit" ), NULL,
1716 N_( "Edit toolkits" ),
1717 G_CALLBACK( mainw_program_new_action_cb ) }
1718 };
1719
1720 static GtkToggleActionEntry mainw_toggle_actions[] = {
1721 { "AutoRecalculate",
1722 NULL, N_( "Au_to Recalculate" ), NULL,
1723 N_( "Recalculate automatically on change" ),
1724 G_CALLBACK( mainw_autorecalc_action_cb ), TRUE },
1725
1726 { "Lock",
1727 NULL, N_( "_Lock tab" ), NULL,
1728 N_( "Lock tab" ),
1729 G_CALLBACK( mainw_lock_action_cb ), TRUE },
1730
1731 { "Toolbar",
1732 NULL, N_( "_Toolbar" ), NULL,
1733 N_( "Show window toolbar" ),
1734 G_CALLBACK( mainw_toolbar_action_cb ), TRUE },
1735
1736 { "Statusbar",
1737 NULL, N_( "_Statusbar" ), NULL,
1738 N_( "Show window statusbar" ),
1739 G_CALLBACK( mainw_statusbar_action_cb ), TRUE },
1740
1741 { "ToolkitBrowser",
1742 NULL, N_( "Toolkit _Browser" ), NULL,
1743 N_( "Show toolkit browser" ),
1744 G_CALLBACK( mainw_toolkitbrowser_action_cb ), FALSE },
1745
1746 { "Tabdefs",
1747 NULL, N_( "Tab _Definitions" ), NULL,
1748 N_( "Show tab definitions" ),
1749 G_CALLBACK( mainw_tabdefs_action_cb ), FALSE },
1750 };
1751
1752 static GtkRadioActionEntry mainw_radio_actions[] = {
1753 { "Normal",
1754 NULL, N_( "_Normal" ), NULL,
1755 N_( "Normal view mode" ),
1756 WORKSPACE_MODE_REGULAR },
1757
1758 { "ShowFormula",
1759 NULL, N_( "Show _Formula" ), NULL,
1760 N_( "Show formula view mode" ),
1761 WORKSPACE_MODE_FORMULA },
1762
1763 { "NoEdit",
1764 NULL, N_( "No _Edits" ), NULL,
1765 N_( "No edits view mode" ),
1766 WORKSPACE_MODE_NOEDIT },
1767 };
1768
1769 static const char *mainw_menubar_ui_description =
1770 "<ui>"
1771 " <menubar name='MainwMenubar'>"
1772 " <menu action='FileMenu'>"
1773 " <menu action='NewMenu'>"
1774 " <menuitem action='NewColumnName'/>"
1775 " <menuitem action='NewTab'/>"
1776 " <menuitem action='NewWorkspace'/>"
1777 " </menu>"
1778 " <menuitem action='Open'/>"
1779 " <menu action='RecentMenu'>"
1780 " <menuitem action='Stub'/>" /* Dummy ... replaced on map */
1781 " </menu>"
1782 " <menuitem action='OpenExamples'/>"
1783 " <separator/>"
1784 " <menuitem action='DuplicateWorkspace'/>"
1785 " <menuitem action='Merge'/>"
1786 " <menuitem action='Save'/>"
1787 " <menuitem action='SaveAs'/>"
1788 " <separator/>"
1789 " <menuitem action='Recover'/>"
1790 " <separator/>"
1791 " <menuitem action='Close'/>"
1792 " <menuitem action='Quit'/>"
1793 " </menu>"
1794 " <menu action='EditMenu'>"
1795 " <menuitem action='Delete'/>"
1796 " <menuitem action='SelectAll'/>"
1797 " <menuitem action='Duplicate'/>"
1798 " <menuitem action='Recalculate'/>"
1799 " <menuitem action='AutoRecalculate'/>"
1800 " <menuitem action='Lock'/>"
1801 " <separator/>"
1802 " <menuitem action='Find'/>"
1803 " <menuitem action='FindNext'/>"
1804 " <menuitem action='NextError'/>"
1805 " <menu action='JumpToColumnMenu'>"
1806 " <menuitem action='Stub'/>" /* Dummy ... replaced on map */
1807 " </menu>"
1808 " <separator/>"
1809 " <menuitem action='Group'/>"
1810 " <menuitem action='Ungroup'/>"
1811 " <separator/>"
1812 " <menuitem action='Preferences'/>"
1813 " </menu>"
1814 " <menu action='ViewMenu'>"
1815 " <menuitem action='Toolbar'/>"
1816 " <menuitem action='Statusbar'/>"
1817 " <menuitem action='ToolkitBrowser'/>"
1818 " <menuitem action='Tabdefs'/>"
1819 " <separator/>"
1820 #ifdef HAVE_LIBGVC
1821 " <menuitem action='Graph'/>"
1822 " <separator/>"
1823 #endif /*HAVE_LIBGVC*/
1824 " <menuitem action='Normal'/>"
1825 " <menuitem action='ShowFormula'/>"
1826 " <menuitem action='NoEdit'/>"
1827 " </menu>"
1828 " <menu action='ToolkitsMenu'>"
1829 " <menuitem action='EditToolkits'/>"
1830 " <separator/>"
1831 " <menuitem action='Stub'/>" /* Toolkits pasted here at runtime */
1832 " </menu>"
1833 " <menu action='HelpMenu'>"
1834 " <menuitem action='Guide'/>"
1835 " <menuitem action='About'/>"
1836 " <separator/>"
1837 " <menuitem action='Homepage'/>"
1838 " </menu>"
1839 " </menubar>"
1840 "</ui>";
1841
1842 static const char *mainw_toolbar_ui_description =
1843 "<ui>"
1844 " <toolbar name='MainwToolbar'>"
1845 " <toolitem action='Open'/>"
1846 " <toolitem action='SaveAs'/>"
1847 " <toolitem action='NewWorkspace'/>"
1848 " <toolitem action='DuplicateWorkspace'/>"
1849 " <separator/>"
1850 " <toolitem action='NewColumn'/>"
1851 " <toolitem action='Duplicate'/>"
1852 " </toolbar>"
1853 "</ui>";
1854
1855 static void
mainw_watch_changed_cb(Watchgroup * watchgroup,Watch * watch,Mainw * mainw)1856 mainw_watch_changed_cb( Watchgroup *watchgroup, Watch *watch, Mainw *mainw )
1857 {
1858 if( strcmp( IOBJECT( watch )->name, "MAINW_TOOLBAR_STYLE" ) == 0 )
1859 mainw->toolbar_visible = MAINW_TOOLBAR;
1860
1861 mainw_refresh( mainw );
1862 }
1863
1864 /* Make the insides of the panel.
1865 */
1866 static void
mainw_build(iWindow * iwnd,GtkWidget * vbox)1867 mainw_build( iWindow *iwnd, GtkWidget *vbox )
1868 {
1869 Mainw *mainw = MAINW( iwnd );
1870
1871 GtkWidget *mbar;
1872 GtkWidget *frame;
1873 GError *error;
1874 GtkWidget *cancel;
1875 GtkWidget *item;
1876
1877 #ifdef DEBUG
1878 printf( "mainw_build: %p\n", mainw );
1879 #endif /*DEBUG*/
1880
1881 /* Make main menu bar
1882 */
1883 gtk_action_group_add_actions( iwnd->action_group,
1884 mainw_actions, G_N_ELEMENTS( mainw_actions ),
1885 GTK_WINDOW( mainw ) );
1886 gtk_action_group_add_toggle_actions( iwnd->action_group,
1887 mainw_toggle_actions, G_N_ELEMENTS( mainw_toggle_actions ),
1888 GTK_WINDOW( mainw ) );
1889 gtk_action_group_add_radio_actions( iwnd->action_group,
1890 mainw_radio_actions, G_N_ELEMENTS( mainw_radio_actions ),
1891 WORKSPACE_MODE_REGULAR,
1892 G_CALLBACK( mainw_mode_action_cb ),
1893 GTK_WINDOW( mainw ) );
1894
1895 error = NULL;
1896 if( !gtk_ui_manager_add_ui_from_string( iwnd->ui_manager,
1897 mainw_menubar_ui_description, -1, &error ) ||
1898 !gtk_ui_manager_add_ui_from_string( iwnd->ui_manager,
1899 mainw_toolbar_ui_description, -1, &error ) ) {
1900 g_message( "building menus failed: %s", error->message );
1901 g_error_free( error );
1902 exit( EXIT_FAILURE );
1903 }
1904
1905 mbar = gtk_ui_manager_get_widget( iwnd->ui_manager, "/MainwMenubar" );
1906 gtk_box_pack_start( GTK_BOX( vbox ), mbar, FALSE, FALSE, 0 );
1907 gtk_widget_show( mbar );
1908
1909 /* Get the dummy item on the recent menu, then get the enclosing menu
1910 * for that dummy item.
1911 */
1912 item = gtk_ui_manager_get_widget( iwnd->ui_manager,
1913 "/MainwMenubar/FileMenu/RecentMenu/Stub" );
1914 mainw->recent_menu = gtk_widget_get_parent( GTK_WIDGET( item ) );
1915 gtk_signal_connect( GTK_OBJECT( mainw->recent_menu ), "map",
1916 GTK_SIGNAL_FUNC( mainw_recent_map_cb ), mainw );
1917
1918 /* Same for the column jump menu.
1919 */
1920 item = gtk_ui_manager_get_widget( iwnd->ui_manager,
1921 "/MainwMenubar/EditMenu/JumpToColumnMenu/Stub" );
1922 mainw->jump_to_column_menu =
1923 gtk_widget_get_parent( GTK_WIDGET( item ) );
1924
1925 /* Same for the tk menu.
1926 */
1927 item = gtk_ui_manager_get_widget( iwnd->ui_manager,
1928 "/MainwMenubar/ToolkitsMenu/Stub" );
1929 mainw->toolkit_menu = gtk_widget_get_parent( GTK_WIDGET( item ) );
1930 gtk_widget_destroy( item );
1931
1932 /* Attach toolbar.
1933 */
1934 mainw->toolbar = gtk_ui_manager_get_widget(
1935 iwnd->ui_manager, "/MainwToolbar" );
1936 gtk_box_pack_start( GTK_BOX( vbox ), mainw->toolbar, FALSE, FALSE, 0 );
1937 widget_visible( mainw->toolbar, MAINW_TOOLBAR );
1938
1939 /* This will set to NULL if we don't have infobar support.
1940 */
1941 if( (IWINDOW( mainw )->infobar = infobar_new()) )
1942 gtk_box_pack_start( GTK_BOX( vbox ),
1943 GTK_WIDGET( IWINDOW( mainw )->infobar ),
1944 FALSE, FALSE, 0 );
1945
1946 /* hbox for status bar etc.
1947 */
1948 mainw->statusbar_main = gtk_hbox_new( FALSE, 2 );
1949 gtk_box_pack_end( GTK_BOX( vbox ),
1950 mainw->statusbar_main, FALSE, FALSE, 2 );
1951 widget_visible( mainw->statusbar_main, MAINW_STATUSBAR );
1952
1953 /* Make space free label.
1954 */
1955 mainw->space_free_eb = gtk_event_box_new();
1956 gtk_box_pack_start( GTK_BOX( mainw->statusbar_main ),
1957 mainw->space_free_eb, FALSE, FALSE, 0 );
1958 gtk_widget_show( mainw->space_free_eb );
1959 frame = gtk_frame_new( NULL );
1960 gtk_frame_set_shadow_type( GTK_FRAME( frame ), GTK_SHADOW_IN );
1961 gtk_container_add( GTK_CONTAINER( mainw->space_free_eb ), frame );
1962 gtk_widget_show( frame );
1963 mainw->space_free = gtk_label_new( "space_free" );
1964 gtk_misc_set_padding( GTK_MISC( mainw->space_free ), 2, 2 );
1965 gtk_container_add( GTK_CONTAINER( frame ), mainw->space_free );
1966 gtk_signal_connect( GTK_OBJECT( mainw->space_free_eb ), "event",
1967 GTK_SIGNAL_FUNC( mainw_space_free_event ), mainw );
1968 set_tooltip_generate( mainw->space_free_eb,
1969 (TooltipGenerateFn) mainw_space_free_tooltip_generate,
1970 mainw, NULL );
1971 gtk_widget_show( mainw->space_free );
1972 mainw->imageinfo_changed_sid = g_signal_connect( main_imageinfogroup,
1973 "changed",
1974 G_CALLBACK( mainw_free_changed_cb ), mainw );
1975 mainw->heap_changed_sid = g_signal_connect( reduce_context->heap,
1976 "changed",
1977 G_CALLBACK( mainw_free_changed_cb ), mainw );
1978
1979 /* Make message label.
1980 */
1981 mainw->statusbar = gtk_label_new( "" );
1982 gtk_label_set_ellipsize( GTK_LABEL( mainw->statusbar ),
1983 PANGO_ELLIPSIZE_MIDDLE );
1984 /* 6 is enough to stop the statusbar changing height when the progress
1985 * indicator changes visibility.
1986 */
1987 gtk_misc_set_padding( GTK_MISC( mainw->statusbar ), 2, 6 );
1988 gtk_misc_set_alignment( GTK_MISC( mainw->statusbar ), 0.0, 0.5 );
1989 gtk_box_pack_start( GTK_BOX( mainw->statusbar_main ),
1990 mainw->statusbar, TRUE, TRUE, 0 );
1991 gtk_widget_show( mainw->statusbar );
1992
1993 mainw->progress_box = gtk_hbox_new( FALSE, 2 );
1994
1995 mainw->progress = gtk_progress_bar_new();
1996 gtk_widget_set_size_request( GTK_WIDGET( mainw->progress ), 200, -1 );
1997 gtk_box_pack_end( GTK_BOX( mainw->progress_box ), mainw->progress,
1998 FALSE, TRUE, 0 );
1999 gtk_widget_show( mainw->progress );
2000
2001 cancel = gtk_button_new_with_label( "Cancel" );
2002 g_signal_connect( cancel, "clicked",
2003 G_CALLBACK( mainw_cancel_cb ), mainw );
2004 gtk_box_pack_end( GTK_BOX( mainw->progress_box ), cancel,
2005 FALSE, TRUE, 0 );
2006 gtk_widget_show( cancel );
2007
2008 gtk_box_pack_end( GTK_BOX( mainw->statusbar_main ),
2009 mainw->progress_box, FALSE, TRUE, 0 );
2010
2011 mainw->wsgview = WORKSPACEGROUPVIEW( workspacegroupview_new() );
2012 gtk_box_pack_start( GTK_BOX( vbox ),
2013 GTK_WIDGET( mainw->wsgview ), TRUE, TRUE, 0 );
2014 view_link( VIEW( mainw->wsgview ), MODEL( mainw->wsg ), NULL );
2015 gtk_widget_show( GTK_WIDGET( mainw->wsgview ) );
2016
2017 /* Any changes to prefs, refresh (yuk!).
2018 */
2019 mainw->watch_changed_sid = g_signal_connect( main_watchgroup,
2020 "watch_changed",
2021 G_CALLBACK( mainw_watch_changed_cb ), mainw );
2022 }
2023
2024 static void
mainw_popdown(iWindow * iwnd,void * client,iWindowNotifyFn nfn,void * sys)2025 mainw_popdown( iWindow *iwnd, void *client, iWindowNotifyFn nfn, void *sys )
2026 {
2027 Mainw *mainw = MAINW( iwnd );
2028
2029 /* We can be destroyed in two ways: either our iwnd tells us to go, or
2030 * our model is destroyed under us. If the model has gone, we just go.
2031 * If the model is still there, we need to ask about saving and
2032 * quitting.
2033 */
2034
2035 if( mainw->wsg )
2036 filemodel_inter_savenclose_cb( IWINDOW( mainw ),
2037 FILEMODEL( mainw->wsg ), nfn, sys );
2038 else
2039 nfn( sys, IWINDOW_YES );
2040 }
2041
2042 static void
mainw_wsg_changed_cb(Workspacegroup * wsg,Mainw * mainw)2043 mainw_wsg_changed_cb( Workspacegroup *wsg, Mainw *mainw )
2044 {
2045 mainw_refresh( mainw );
2046 }
2047
2048 static void
mainw_wsg_destroy_cb(Workspacegroup * wsg,Mainw * mainw)2049 mainw_wsg_destroy_cb( Workspacegroup *wsg, Mainw *mainw )
2050 {
2051 mainw->wsg = NULL;
2052 }
2053
2054 static void
mainw_link(Mainw * mainw,Workspacegroup * wsg)2055 mainw_link( Mainw *mainw, Workspacegroup *wsg )
2056 {
2057 Workspace *ws = workspacegroup_get_workspace( wsg );
2058
2059 /* Take ownership of the wsg.
2060 */
2061 mainw->wsg = wsg;
2062 g_object_ref( G_OBJECT( mainw->wsg ) );
2063 iobject_sink( IOBJECT( mainw->wsg ) );
2064
2065 wsg->iwnd = IWINDOW( mainw );
2066
2067 iwindow_set_build( IWINDOW( mainw ),
2068 (iWindowBuildFn) mainw_build, wsg, NULL, NULL );
2069 iwindow_set_popdown( IWINDOW( mainw ), mainw_popdown, NULL );
2070 iwindow_set_size_prefs( IWINDOW( mainw ),
2071 "MAINW_WINDOW_WIDTH", "MAINW_WINDOW_HEIGHT" );
2072 iwindow_build( IWINDOW( mainw ) );
2073
2074 if( ws &&
2075 MODEL( ws )->window_width != - 1 )
2076 gtk_window_set_default_size( GTK_WINDOW( mainw ),
2077 MODEL( ws )->window_width,
2078 MODEL( ws )->window_height );
2079
2080 /* Set start state.
2081 */
2082 (void) mainw_refresh( mainw );
2083
2084 mainw->changed_sid = g_signal_connect( mainw->wsg,
2085 "changed",
2086 G_CALLBACK( mainw_wsg_changed_cb ), mainw );
2087 mainw->destroy_sid = g_signal_connect( mainw->wsg,
2088 "destroy",
2089 G_CALLBACK( mainw_wsg_destroy_cb ), mainw );
2090 }
2091
2092 Mainw *
mainw_new(Workspacegroup * wsg)2093 mainw_new( Workspacegroup *wsg )
2094 {
2095 Mainw *mainw;
2096
2097 mainw = MAINW( g_object_new( TYPE_MAINW, NULL ) );
2098
2099 mainw_link( mainw, wsg );
2100
2101 return( mainw );
2102 }
2103
2104 static void *
mainw_cull_sub(Mainw * mainw)2105 mainw_cull_sub( Mainw *mainw )
2106 {
2107 if( !ICONTAINER( mainw->wsg )->children ) {
2108 filemodel_set_modified( FILEMODEL( mainw->wsg ), FALSE );
2109 iwindow_kill( IWINDOW( mainw ) );
2110 }
2111
2112 return( NULL );
2113 }
2114
2115 void
mainw_cull(void)2116 mainw_cull( void )
2117 {
2118 slist_map( mainw_all,
2119 (SListMapFn) mainw_cull_sub, NULL );
2120 }
2121
2122 static void *
mainw_layout_sub(Workspace * ws)2123 mainw_layout_sub( Workspace *ws )
2124 {
2125 model_layout( MODEL( ws ) );
2126 workspace_set_needs_layout( ws, FALSE );
2127
2128 return( NULL );
2129 }
2130
2131 static gboolean
mainw_layout_timeout_cb(gpointer user_data)2132 mainw_layout_timeout_cb( gpointer user_data )
2133 {
2134 mainw_layout_timeout = 0;
2135
2136 slist_map( workspace_get_needs_layout(),
2137 (SListMapFn) mainw_layout_sub, NULL );
2138
2139 return( FALSE );
2140 }
2141
2142 void
mainw_layout(void)2143 mainw_layout( void )
2144 {
2145 IM_FREEF( g_source_remove, mainw_layout_timeout );
2146 mainw_layout_timeout = g_timeout_add( 300,
2147 (GSourceFunc) mainw_layout_timeout_cb, NULL );
2148 }
2149