~ubuntu-branches/debian/jessie/arb/jessie

« back to all changes in this revision

Viewing changes to WINDOW/AW_root.cxx

  • Committer: Package Import Robot
  • Author(s): Elmar Pruesse, Andreas Tille, Elmar Pruesse
  • Date: 2014-09-02 15:15:06 UTC
  • mfrom: (1.1.6)
  • Revision ID: package-import@ubuntu.com-20140902151506-jihq58b3iz342wif
Tags: 6.0.2-1
[ Andreas Tille ]
* New upstream version
  Closes: #741890
* debian/upstream -> debian/upstream/metadata
* debian/control:
   - Build-Depends: added libglib2.0-dev
   - Depends: added mafft, mrbayes
* debian/rules
   - Add explicite --remove-section=.comment option to manual strip call
* cme fix dpkg-control
* arb-common.dirs: Do not create unneeded lintian dir
* Add turkish debconf translation (thanks for the patch to Mert Dirik
  <mertdirik@gmail.com>)
  Closes: #757497

[ Elmar Pruesse ]
* patches removed:
   - 10_config.makefiles.patch,
     80_no_GL.patch
       removed in favor of creating file from config.makefile.template via 
       sed in debian/control
   - 20_Makefile_main.patch
       merged upstream
   - 21_Makefiles.patch
       no longer needed
   - 30_tmpfile_CVE-2008-5378.patch: 
       merged upstream
   - 50_fix_gcc-4.8.patch:
       merged upstream
   - 40_add_libGLU.patch:
       libGLU not needed for arb_ntree)
   - 60_use_debian_packaged_raxml.patch:
       merged upstream
   - 70_hardening.patch
       merged upstream
   - 72_add_math_lib_to_linker.patch
       does not appear to be needed
* patches added:
   - 10_upstream_r12793__show_db_load_progress:
       backported patch showing progress while ARB is loading a database
       (needed as indicator/splash screen while ARB is launching)
   - 20_upstream_r12794__socket_permissions:
       backported security fix
   - 30_upstream_r12814__desktop_keywords:
       backported add keywords to desktop (fixes lintian warning)
   - 40_upstream_r12815__lintian_spelling:
       backported fix for lintian reported spelling errors
   - 50_private_nameservers
       change configuration to put nameservers into users home dirs
       (avoids need for shared writeable directory)
   - 60_use_debian_phyml
       use phyml from debian package for both interfaces in ARB
* debian/rules:
   - create config.makefile from override_dh_configure target
   - use "make tarfile" in override_dh_install
   - remove extra cleaning not needed for ARB 6
   - use "dh_install --list-missing" to avoid missing files
   - added override_dh_fixperms target
* debian/control:
   - added libarb-dev package
   - Depends: added phyml, xdg-utils
   - Suggests: removed phyml
   - fix lintian duplicate-short-description (new descriptions)
* debian/*.install:
   - "unrolled" confusing globbing to select files
   - pick files from debian/tmp
   - moved all config files to /etc/arb
* debian/arb-common.templates: updated
* scripts:
   - removed arb-add-pt-server
   - launch-wrapper: 
     - only add demo.arb to newly created $ARBUSERDATA
     - pass commandline arguments through bin/arb wrapper
   - preinst: removing old PT server index files on upgrade from 5.5*
   - postinst: set setgid on shared PT dir
* rewrote arb.1 manfile
* added file icon for ARB databases
* using upstream arb_tcp.dat

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// =============================================================== //
 
2
//                                                                 //
 
3
//   File      : AW_root.cxx                                       //
 
4
//   Purpose   :                                                   //
 
5
//                                                                 //
 
6
//   Institute of Microbiology (Technical University Munich)       //
 
7
//   http://www.arb-home.de/                                       //
 
8
//                                                                 //
 
9
// =============================================================== //
 
10
 
 
11
#include "aw_root.hxx"
 
12
#include "aw_awar.hxx"
 
13
#include "aw_nawar.hxx"
 
14
#include "aw_msg.hxx"
 
15
#include "aw_window.hxx"
 
16
#include "aw_window_Xm.hxx"
 
17
#include "aw_status.hxx"
 
18
#include "aw_xkey.hxx"
 
19
 
 
20
#include <arb_handlers.h>
 
21
#include <arbdbt.h>
 
22
 
 
23
#include <list>
 
24
 
 
25
#include <X11/cursorfont.h>
 
26
 
 
27
AW_root *AW_root::SINGLETON = NULL;
 
28
 
 
29
void AW_system(AW_window *aww, const char *command, const char *auto_help_file) {
 
30
    if (auto_help_file) AW_help_popup(aww, auto_help_file);
 
31
    aw_message_if(GBK_system(command));
 
32
}
 
33
 
 
34
void AW_clock_cursor(AW_root *awr) {
 
35
    awr->prvt->set_cursor(0, 0, awr->prvt->clock_cursor);
 
36
}
 
37
 
 
38
void AW_normal_cursor(AW_root *awr) {
 
39
    awr->prvt->set_cursor(0, 0, 0);
 
40
}
 
41
 
 
42
void AW_help_entry_pressed(AW_window *aww) {
 
43
    AW_root *root = aww->get_root();
 
44
    p_global->help_active = 1;
 
45
}
 
46
 
 
47
void AW_root::process_events() {
 
48
    XtAppProcessEvent(p_r->context, XtIMAll);
 
49
}
 
50
void AW_root::process_pending_events() {
 
51
    XtInputMask pending = XtAppPending(p_r->context);
 
52
    while (pending) {
 
53
        XtAppProcessEvent(p_r->context, pending);
 
54
        pending = XtAppPending(p_r->context);
 
55
    }
 
56
}
 
57
 
 
58
 
 
59
AW_ProcessEventType AW_root::peek_key_event(AW_window *) {
 
60
    //! Returns type if key event follows, else 0
 
61
 
 
62
    XEvent xevent;
 
63
    Boolean result = XtAppPeekEvent(p_r->context, &xevent);
 
64
 
 
65
    if (!result) return NO_EVENT;
 
66
    if ((xevent.type != KeyPress) && (xevent.type != KeyRelease)) return NO_EVENT;
 
67
    return (AW_ProcessEventType)xevent.type;
 
68
}
 
69
 
 
70
AW_default AW_root::load_properties(const char *default_name) {
 
71
    GBDATA   *gb_default = GB_open(default_name, "rwcD");
 
72
    GB_ERROR  error;
 
73
 
 
74
    if (gb_default) {
 
75
        error = GB_no_transaction(gb_default);
 
76
        if (!error) {
 
77
            GBDATA *gb_tmp = GB_search(gb_default, "tmp", GB_CREATE_CONTAINER);
 
78
            error          = GB_set_temporary(gb_tmp);
 
79
        }
 
80
    }
 
81
    else {
 
82
        error = GB_await_error();
 
83
    }
 
84
 
 
85
    if (error) {
 
86
        const char *shown_name      = strrchr(default_name, '/');
 
87
        if (!shown_name) shown_name = default_name;
 
88
 
 
89
        GBK_terminatef("Error loading properties '%s': %s", shown_name, error);
 
90
    }
 
91
 
 
92
    return (AW_default) gb_default;
 
93
}
 
94
 
 
95
static void destroy_AW_root() {
 
96
    delete AW_root::SINGLETON;
 
97
    AW_root::SINGLETON = NULL;
 
98
}
 
99
 
 
100
 
 
101
bool AW_root::is_focus_callback(AW_RCB fcb) const { // eliminated in gtk-branch
 
102
    return focus_callback_list && focus_callback_list->contains(makeRootCallback(fcb, AW_CL(0), AW_CL(0)));
 
103
}
 
104
 
 
105
AW_root::AW_root(const char *propertyFile, const char *program, bool no_exit, UserActionTracker *user_tracker, int */*argc*/, char ***/*argv*/) {
 
106
    aw_assert(!AW_root::SINGLETON);                 // only one instance allowed
 
107
    AW_root::SINGLETON = this;
 
108
 
 
109
    memset((char *)this, 0, sizeof(AW_root));
 
110
 
 
111
    prvt = new AW_root_Motif;
 
112
 
 
113
    init_variables(load_properties(propertyFile));
 
114
    init_root(program, no_exit);
 
115
 
 
116
    tracker = user_tracker;
 
117
 
 
118
    atexit(destroy_AW_root); // do not call this before opening properties DB!
 
119
}
 
120
 
 
121
#if defined(UNIT_TESTS)
 
122
AW_root::AW_root(const char *propertyFile) {
 
123
    aw_assert(!AW_root::SINGLETON);                 // only one instance allowed
 
124
    AW_root::SINGLETON = this;
 
125
 
 
126
    memset((char *)this, 0, sizeof(AW_root));
 
127
    init_variables(load_properties(propertyFile));
 
128
    atexit(destroy_AW_root); // do not call this before opening properties DB!
 
129
}
 
130
#endif
 
131
 
 
132
void AW_root::setUserActionTracker(UserActionTracker *user_tracker) {
 
133
    aw_assert(user_tracker);
 
134
    aw_assert(tracker->is_replaceable()); // there is already another tracker (program-logic-error)
 
135
 
 
136
    delete tracker;
 
137
    tracker = user_tracker;
 
138
}
 
139
 
 
140
AW_awar *AW_root::label_is_awar(const char *label) {
 
141
    AW_awar *awar_exists = NULL;
 
142
    size_t   off         = strcspn(label, "/ ");
 
143
 
 
144
    if (label[off] == '/') {                        // contains '/' and no space before first '/'
 
145
        awar_exists = awar_no_error(label);
 
146
    }
 
147
    return awar_exists;
 
148
}
 
149
 
 
150
void AW_root::define_remote_command(AW_cb *cbs) {
 
151
    if (cbs->contains(AW_CB(AW_POPDOWN))) {
 
152
        aw_assert(!cbs->get_cd1() && !cbs->get_cd2()); // popdown takes no parameters (please pass ", 0, 0"!)
 
153
    }
 
154
 
 
155
    AW_cb *old_cbs = (AW_cb*)GBS_write_hash(prvt->action_hash, cbs->id, (long)cbs);
 
156
    if (old_cbs) {
 
157
        if (!old_cbs->is_equal(*cbs)) {                  // existing remote command replaced by different callback
 
158
#if defined(DEBUG)
 
159
            fputs(GBS_global_string("Warning: reused callback id '%s' for different callback\n", old_cbs->id), stderr);
 
160
#if defined(DEVEL_RALF) && 1
 
161
            aw_assert(0);
 
162
#endif // DEVEL_RALF
 
163
#endif // DEBUG
 
164
        }
 
165
        // do not free old_cbs, cause it's still reachable from first widget that defined this remote command
 
166
    }
 
167
}
 
168
 
 
169
AW_cb *AW_root::search_remote_command(const char *action) {
 
170
    return (AW_cb *)GBS_read_hash(prvt->action_hash, action);
 
171
}
 
172
 
 
173
static long set_focus_policy(const char *, long cl_aww, void *) {
 
174
    AW_window *aww = (AW_window*)cl_aww;
 
175
    aww->set_focus_policy(aww->get_root()->focus_follows_mouse);
 
176
    return cl_aww;
 
177
}
 
178
void AW_root::apply_focus_policy(bool follow_mouse) {
 
179
    focus_follows_mouse = follow_mouse;
 
180
    GBS_hash_do_loop(hash_for_windows, set_focus_policy, 0);
 
181
}
 
182
 
 
183
void AW_root::apply_sensitivity(AW_active mask) {
 
184
    aw_assert(legal_mask(mask));
 
185
    AW_buttons_struct *list;
 
186
 
 
187
    global_mask = mask;
 
188
    for (list = button_sens_list; list; list = list->next) {
 
189
        XtSetSensitive(list->button, (list->mask & mask) ? True : False);
 
190
    }
 
191
}
 
192
 
 
193
 
 
194
struct fallbacks {
 
195
    const char *fb;
 
196
    const char *awar;
 
197
    const char *init;
 
198
};
 
199
 
 
200
static struct fallbacks aw_fb[] = {
 
201
    // Name         fallback awarname    default value
 
202
    { "FontList",   "window/font",       "8x13bold" },
 
203
    { "background", "window/background", "grey" },
 
204
    { "foreground", "window/foreground", "Black", },
 
205
    { 0,            "window/color_1",    "red", },
 
206
    { 0,            "window/color_2",    "green", },
 
207
    { 0,            "window/color_3",    "blue", },
 
208
    { 0,            0,                   0 }
 
209
};
 
210
 
 
211
 
 
212
void AW_root::init_variables(AW_default database) {
 
213
    application_database     = database;
 
214
    hash_table_for_variables = GBS_create_hash(1000, GB_MIND_CASE);
 
215
    hash_for_windows         = GBS_create_hash(100, GB_MIND_CASE);
 
216
 
 
217
    for (int i=0; aw_fb[i].awar; ++i) {
 
218
        awar_string(aw_fb[i].awar, aw_fb[i].init, application_database);
 
219
    }
 
220
}
 
221
 
 
222
static void aw_message_and_dump_stderr(const char *msg) {
 
223
    fflush(stdout);
 
224
    fprintf(stderr, "ARB: %s\n", msg); // print to console as well
 
225
    fflush(stderr);
 
226
    aw_message(msg);
 
227
}
 
228
static void dump_stdout(const char *msg) {
 
229
    fprintf(stdout, "ARB: %s\n", msg);
 
230
}
 
231
 
 
232
static arb_status_implementation AW_status_impl = {
 
233
    AST_RANDOM, 
 
234
    aw_openstatus,
 
235
    aw_closestatus,
 
236
    aw_status_title, // set_title
 
237
    AW_status, // set_subtitle
 
238
    AW_status, // set_gauge
 
239
    AW_status, // user_abort
 
240
};
 
241
 
 
242
static arb_handlers aw_handlers = {
 
243
    aw_message_and_dump_stderr,
 
244
    aw_message,
 
245
    dump_stdout,
 
246
    AW_status_impl, 
 
247
};
 
248
 
 
249
void AW_root::init_root(const char *programname, bool no_exit) {
 
250
    // initialize ARB X application
 
251
    int          a             = 0;
 
252
    XFontStruct *fontstruct;
 
253
    const int    MAX_FALLBACKS = 30;
 
254
    char        *fallback_resources[MAX_FALLBACKS];
 
255
 
 
256
    prvt->action_hash = GBS_create_hash(1000, GB_MIND_CASE);
 
257
 
 
258
    p_r-> no_exit = no_exit;
 
259
    program_name  = strdup(programname);
 
260
 
 
261
    int i;
 
262
    for (i=0; aw_fb[i].fb; i++) {
 
263
        GBDATA *gb_awar       = GB_search((GBDATA*)application_database, aw_fb[i].awar, GB_FIND);
 
264
        fallback_resources[i] = GBS_global_string_copy("*%s: %s", aw_fb[i].fb, GB_read_char_pntr(gb_awar));
 
265
    }
 
266
    fallback_resources[i] = 0;
 
267
    aw_assert(i<MAX_FALLBACKS);
 
268
 
 
269
    ARB_install_handlers(aw_handlers);
 
270
 
 
271
    // @@@ FIXME: the next line hangs if program runs inside debugger
 
272
    p_r->toplevel_widget = XtOpenApplication(&(p_r->context), programname,
 
273
            NULL, 0, // XrmOptionDescRec+numOpts
 
274
            &a, // &argc
 
275
            NULL, // argv
 
276
            fallback_resources,
 
277
            applicationShellWidgetClass, // widget class
 
278
            NULL, 0);
 
279
 
 
280
    for (i=0; fallback_resources[i]; i++) free(fallback_resources[i]);
 
281
 
 
282
    p_r->display = XtDisplay(p_r->toplevel_widget);
 
283
 
 
284
    if (p_r->display == NULL) {
 
285
        printf("cannot open display\n");
 
286
        exit(EXIT_FAILURE);
 
287
    }
 
288
    {
 
289
        GBDATA *gbd = (GBDATA*)application_database;
 
290
        const char *font = GB_read_char_pntr(GB_search(gbd, "window/font", GB_FIND));
 
291
        if (!(fontstruct = XLoadQueryFont(p_r->display, font))) {
 
292
            if (!(fontstruct = XLoadQueryFont(p_r->display, "fixed"))) {
 
293
                printf("can not load font\n");
 
294
                exit(EXIT_FAILURE);
 
295
            }
 
296
        }
 
297
    }
 
298
 
 
299
    if (fontstruct->max_bounds.width == fontstruct->min_bounds.width) {
 
300
        font_width = fontstruct->max_bounds.width;
 
301
    }
 
302
    else {
 
303
        font_width = (fontstruct->min_bounds.width
 
304
                + fontstruct->max_bounds.width) / 2;
 
305
    }
 
306
 
 
307
    font_height = fontstruct->max_bounds.ascent
 
308
            + fontstruct->max_bounds.descent;
 
309
    font_ascent = fontstruct->max_bounds.ascent;
 
310
 
 
311
    p_r->fontlist = XmFontListCreate(fontstruct, XmSTRING_DEFAULT_CHARSET);
 
312
 
 
313
    button_sens_list = 0;
 
314
 
 
315
    p_r->last_option_menu = p_r->current_option_menu = p_r->option_menu_list = NULL;
 
316
    p_r->last_toggle_field = p_r->toggle_field_list = NULL;
 
317
    p_r->last_selection_list = p_r->selection_list = NULL;
 
318
 
 
319
    value_changed = false;
 
320
    y_correction_for_input_labels = 5;
 
321
    global_mask = AWM_ALL;
 
322
 
 
323
    p_r->screen_depth = PlanesOfScreen(XtScreen(p_r->toplevel_widget));
 
324
    if (p_r->screen_depth == 1) {
 
325
        color_mode = AW_MONO_COLOR;
 
326
    }
 
327
    else {
 
328
        color_mode = AW_RGB_COLOR;
 
329
    }
 
330
    p_r->colormap = DefaultColormapOfScreen(XtScreen(p_r->toplevel_widget));
 
331
    p_r->clock_cursor = XCreateFontCursor(XtDisplay(p_r->toplevel_widget), XC_watch);
 
332
    p_r->question_cursor = XCreateFontCursor(XtDisplay(p_r->toplevel_widget), XC_question_arrow);
 
333
 
 
334
    create_colormap();
 
335
    aw_root_init_font(XtDisplay(p_r->toplevel_widget));
 
336
    aw_install_xkeys(XtDisplay(p_r->toplevel_widget));
 
337
 
 
338
}
 
339
 
 
340
AW_root::~AW_root() {
 
341
    delete tracker; tracker = NULL;
 
342
 
 
343
    AW_root_cblist::clear(focus_callback_list);
 
344
    delete button_sens_list;    button_sens_list = NULL;
 
345
 
 
346
    exit_root();
 
347
    exit_variables();
 
348
    aw_assert(this == AW_root::SINGLETON);
 
349
 
 
350
    delete prvt;
 
351
 
 
352
    free(program_name);
 
353
 
 
354
    AW_root::SINGLETON = NULL;
 
355
}
 
356
 
 
357
/**
 
358
 * A list of awar names that contain color names
 
359
 */
 
360
static const char *aw_awar_2_color[] = {
 
361
    "window/background",
 
362
    "window/foreground",
 
363
    "window/color_1",
 
364
    "window/color_2",
 
365
    "window/color_3",
 
366
    0
 
367
};
 
368
 
 
369
void AW_root::create_colormap() {
 
370
 
 
371
    XColor xcolor_returned, xcolor_exakt;
 
372
    GBDATA *gbd = check_properties(NULL);
 
373
    prvt->color_table = (AW_rgb*)GB_calloc(sizeof(AW_rgb), AW_STD_COLOR_IDX_MAX);
 
374
 
 
375
    // Color monitor, B&W monitor is no longer supported
 
376
    const char **awar_2_color;
 
377
    int color;
 
378
    for (color = 0, awar_2_color = aw_awar_2_color;
 
379
         *awar_2_color;
 
380
         awar_2_color++, color++)
 
381
    {
 
382
        const char *name_of_color = GB_read_char_pntr(GB_search(gbd, *awar_2_color, GB_FIND));
 
383
        if (XAllocNamedColor(prvt->display, prvt->colormap, name_of_color, &xcolor_returned, &xcolor_exakt) == 0) {
 
384
            fprintf(stderr, "XAllocColor failed: %s\n", name_of_color);
 
385
        }
 
386
        else {
 
387
            prvt->color_table[color] = xcolor_returned.pixel;
 
388
        }
 
389
    }
 
390
 
 
391
    prvt->foreground = BlackPixelOfScreen(XtScreen(prvt->toplevel_widget));
 
392
    XtVaGetValues(prvt->toplevel_widget, XmNbackground, &prvt->background, NULL);
 
393
    // AW_WINDOW_DRAG see init_devices
 
394
}
 
395
 
 
396
 
 
397
void AW_root::window_hide(AW_window *aww) {
 
398
    active_windows--;
 
399
    if (active_windows<0) {
 
400
        exit(EXIT_SUCCESS);
 
401
    }
 
402
    if (current_modal_window == aww) {
 
403
        current_modal_window = NULL;
 
404
    }
 
405
}
 
406
void AW_root::window_show() {
 
407
    active_windows++;
 
408
}
 
409
 
 
410
/// begin timer stuff 
 
411
 
 
412
class AW_timer_cb_struct : virtual Noncopyable {
 
413
    AW_root       *awr;
 
414
    TimedCallback  cb;
 
415
 
 
416
    AW_timer_cb_struct(AW_root *aw_root, const TimedCallback& tcb) : awr(aw_root), cb(tcb) {} // use install!
 
417
public:
 
418
 
 
419
    typedef XtTimerCallbackProc timer_callback;
 
420
 
 
421
    static void install(AW_root *aw_root, const TimedCallback& tcb, unsigned ms, timer_callback tc) {
 
422
        AW_timer_cb_struct *tcbs = new AW_timer_cb_struct(aw_root, tcb);
 
423
        tcbs->callAfter(ms, tc);
 
424
    }
 
425
 
 
426
    unsigned call() {
 
427
        return cb(awr);
 
428
    }
 
429
    unsigned callOrDelayIfDisabled() {
 
430
        return awr->disable_callbacks
 
431
            ? 25 // delay by 25 ms
 
432
            : cb(awr);
 
433
    }
 
434
    void callAfter(unsigned ms, timer_callback tc) {
 
435
        XtAppAddTimeOut(awr->prvt->context, ms, tc, this);
 
436
    }
 
437
    void recallOrUninstall(unsigned restart, timer_callback tc) {
 
438
        if (restart) callAfter(restart, tc);
 
439
        else delete this;
 
440
    }
 
441
};
 
442
 
 
443
static void AW_timer_callback(XtPointer aw_timer_cb_struct, XtIntervalId*) {
 
444
    AW_timer_cb_struct *tcbs = (AW_timer_cb_struct *)aw_timer_cb_struct;
 
445
    if (tcbs) {
 
446
        unsigned restart = tcbs->callOrDelayIfDisabled();
 
447
        tcbs->recallOrUninstall(restart, AW_timer_callback);
 
448
    }
 
449
}
 
450
static void AW_timer_callback_never_disabled(XtPointer aw_timer_cb_struct, XtIntervalId*) {
 
451
    AW_timer_cb_struct *tcbs = (AW_timer_cb_struct *)aw_timer_cb_struct;
 
452
    if (tcbs) {
 
453
        unsigned restart = tcbs->call();
 
454
        tcbs->recallOrUninstall(restart, AW_timer_callback_never_disabled);
 
455
    }
 
456
}
 
457
 
 
458
void AW_root::add_timed_callback(int ms, const TimedCallback& tcb) {
 
459
    AW_timer_cb_struct::install(this, tcb, ms, AW_timer_callback);
 
460
}
 
461
void AW_root::add_timed_callback_never_disabled(int ms, const TimedCallback& tcb) {
 
462
    AW_timer_cb_struct::install(this, tcb, ms, AW_timer_callback_never_disabled);
 
463
}
 
464
 
 
465
/// end timer stuff
 
466
 
 
467
/// begin awar stuff
 
468
 
 
469
AW_awar *AW_root::awar_no_error(const char *var_name) {
 
470
    return hash_table_for_variables ? (AW_awar *)GBS_read_hash(hash_table_for_variables, var_name) : NULL;
 
471
}
 
472
 
 
473
 
 
474
AW_awar *AW_root::awar(const char *var_name) {
 
475
    AW_awar *vs = awar_no_error(var_name);
 
476
    if (!vs) GBK_terminatef("AWAR %s not defined", var_name);
 
477
    return vs;
 
478
}
 
479
 
 
480
AW_awar *AW_root::awar_float(const char *var_name, float default_value, AW_default default_file) {
 
481
    AW_awar *vs = awar_no_error(var_name);
 
482
    if (!vs) {
 
483
        default_file = check_properties(default_file);
 
484
        vs           = new AW_awar(AW_FLOAT, var_name, "", (double)default_value, default_file, this);
 
485
        GBS_write_hash(hash_table_for_variables, var_name, (long)vs);
 
486
    }
 
487
    return vs;
 
488
}
 
489
 
 
490
AW_awar *AW_root::awar_string(const char *var_name, const char *default_value, AW_default default_file) {
 
491
    AW_awar *vs = awar_no_error(var_name);
 
492
    if (!vs) {
 
493
        default_file = check_properties(default_file);
 
494
        vs           = new AW_awar(AW_STRING, var_name, default_value, 0, default_file, this);
 
495
        GBS_write_hash(hash_table_for_variables, var_name, (long)vs);
 
496
    }
 
497
    return vs;
 
498
}
 
499
 
 
500
AW_awar *AW_root::awar_int(const char *var_name, long default_value, AW_default default_file) {
 
501
    AW_awar *vs = awar_no_error(var_name);
 
502
    if (!vs) {
 
503
        default_file = check_properties(default_file);
 
504
        vs           = new AW_awar(AW_INT, var_name, (const char *)default_value, 0, default_file, this);
 
505
        GBS_write_hash(hash_table_for_variables, var_name, (long)vs);
 
506
    }
 
507
    return vs;
 
508
}
 
509
 
 
510
AW_awar *AW_root::awar_pointer(const char *var_name, void *default_value, AW_default default_file) {
 
511
    AW_awar *vs = awar_no_error(var_name);
 
512
    if (!vs) {
 
513
        default_file = check_properties(default_file);
 
514
        vs           = new AW_awar(AW_POINTER, var_name, (const char *)default_value, 0.0, default_file, this);
 
515
        GBS_write_hash(hash_table_for_variables, var_name, (long)vs);
 
516
    }
 
517
    return vs;
 
518
}
 
519
 
 
520
static long awar_set_temp_if_is_default(const char *, long val, void *cl_gb_db) {
 
521
    AW_awar *awar = (AW_awar*)val;
 
522
    awar->set_temp_if_is_default((GBDATA*)cl_gb_db);
 
523
    return val;
 
524
}
 
525
 
 
526
void AW_root::dont_save_awars_with_default_value(GBDATA *gb_db) {
 
527
    // this should only be called
 
528
    // - before saving properties
 
529
    // - before saving any main application DB that may contain AWARs
 
530
    //
 
531
    // Bug: Awars created in main DB by clients (e.g. EDIT4) will stay temporary
 
532
    //      and will never be saved again.
 
533
    //
 
534
    // Note: uninstanciated AWARs will not be affected, so different applications with
 
535
    //       different AWAR subsets should be no problem.
 
536
    //       'different applications' here e.g. also includes different calls to arb_ntree
 
537
    //       (e.g. merge-tool, importer, tree-window, ...)
 
538
    //
 
539
    // Problems arise when an awar with the same name is used for two different purposes
 
540
    // or with different default values (regardless whether in properties or main-DB).
 
541
    // But this has already been problematic before.
 
542
 
 
543
    GBS_hash_do_loop(hash_table_for_variables, awar_set_temp_if_is_default, (void*)gb_db);
 
544
}
 
545
 
 
546
void AW_root::main_loop() {
 
547
    XtAppMainLoop(p_r->context);
 
548
}
 
549
 
 
550
static long AW_unlink_awar_from_DB(const char */*key*/, long cl_awar, void *cl_gb_main) {
 
551
    AW_awar *awar    = (AW_awar*)cl_awar;
 
552
    GBDATA  *gb_main = (GBDATA*)cl_gb_main;
 
553
 
 
554
    awar->unlink_from_DB(gb_main);
 
555
    return cl_awar;
 
556
}
 
557
 
 
558
void AW_root::unlink_awars_from_DB(GBDATA *gb_main) {
 
559
    aw_assert(GB_get_root(gb_main) == gb_main);
 
560
 
 
561
    GB_transaction ta(gb_main); // needed in awar-callbacks during unlink
 
562
    GBS_hash_do_loop(hash_table_for_variables, AW_unlink_awar_from_DB, gb_main);
 
563
}
 
564
 
 
565
typedef std::list<GBDATA*> DataPointers;
 
566
 
 
567
static GB_ERROR set_parents_with_only_temp_childs_temp(GBDATA *gbd, DataPointers& made_temp) {
 
568
    GB_ERROR error = NULL;
 
569
 
 
570
    if (GB_read_type(gbd) == GB_DB && !GB_is_temporary(gbd)) {
 
571
        bool has_savable_child = false;
 
572
        for (GBDATA *gb_child = GB_child(gbd); gb_child && !error; gb_child = GB_nextChild(gb_child)) {
 
573
            bool is_tmp = GB_is_temporary(gb_child);
 
574
            if (!is_tmp) {
 
575
                error              = set_parents_with_only_temp_childs_temp(gb_child, made_temp);
 
576
                if (!error) is_tmp = GB_is_temporary(gb_child);         // may have changed
 
577
 
 
578
                if (!is_tmp) has_savable_child = true;
 
579
            }
 
580
        }
 
581
        if (!error && !has_savable_child) {
 
582
            error = GB_set_temporary(gbd);
 
583
            made_temp.push_back(gbd);
 
584
        }
 
585
    }
 
586
 
 
587
    return error;
 
588
}
 
589
 
 
590
static GB_ERROR clear_temp_flags(DataPointers& made_temp) {
 
591
    GB_ERROR error = NULL;
 
592
    for (DataPointers::iterator mt = made_temp.begin(); mt != made_temp.end() && !error; ++mt) {
 
593
        error = GB_clear_temporary(*mt);
 
594
    }
 
595
    return error;
 
596
}
 
597
 
 
598
GB_ERROR AW_root::save_properties(const char *filename) {
 
599
    GB_ERROR  error   = NULL;
 
600
    GBDATA   *gb_prop = application_database;
 
601
 
 
602
    if (!gb_prop) {
 
603
        error = "No properties loaded - won't save";
 
604
    }
 
605
    else {
 
606
        error = GB_push_transaction(gb_prop);
 
607
        if (!error) {
 
608
            aw_update_all_window_geometry_awars(this);
 
609
            error = GB_pop_transaction(gb_prop);
 
610
            if (!error) {
 
611
                dont_save_awars_with_default_value(gb_prop);
 
612
 
 
613
                DataPointers made_temp;
 
614
                error             = set_parents_with_only_temp_childs_temp(gb_prop, made_temp); // avoid saving empty containers
 
615
                if (!error) error = GB_save_in_arbprop(gb_prop, filename, "a");
 
616
                if (!error) error = clear_temp_flags(made_temp);
 
617
            }
 
618
        }
 
619
    }
 
620
 
 
621
    return error;
 
622
}