source: tags/ms_r16q2/WINDOW/AW_window.cxx

Last change on this file was 15027, checked in by westram, 8 years ago
  • UNFIX unused AW_window-parameter of AW_help_popup
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 125.8 KB
Line 
1// =============================================================== //
2//                                                                 //
3//   File      : AW_window.cxx                                     //
4//   Purpose   :                                                   //
5//                                                                 //
6//   Institute of Microbiology (Technical University Munich)       //
7//   http://www.arb-home.de/                                       //
8//                                                                 //
9// =============================================================== //
10
11#include "aw_at.hxx"
12#include "aw_nawar.hxx"
13#include "aw_xfig.hxx"
14#include "aw_Xm.hxx"
15#include "aw_window.hxx"
16#include "aw_window_Xm.hxx"
17#include "aw_xkey.hxx"
18#include "aw_select.hxx"
19#include "aw_awar.hxx"
20#include "aw_msg.hxx"
21#include "aw_root.hxx"
22#include "aw_xargs.hxx"
23#include "aw_device_click.hxx"
24
25#include <arbdbt.h>
26#include <arb_file.h>
27#include <arb_str.h>
28#include <arb_strarray.h>
29
30#include <X11/Shell.h>
31#include <Xm/AtomMgr.h>
32#include <Xm/Frame.h>
33#include <Xm/PushB.h>
34#include <Xm/Protocols.h>
35#include <Xm/RowColumn.h>
36#include <Xm/DrawingA.h>
37#include <Xm/Form.h>
38#include <Xm/Separator.h>
39#include <Xm/MainW.h>
40#include <Xm/CascadeB.h>
41#include <Xm/MenuShell.h>
42#include <Xm/ScrollBar.h>
43#include <Xm/MwmUtil.h>
44
45#include "aw_question.hxx"
46
47#include <cctype>
48#include <map>
49#include <string>
50
51void AW_POPDOWN(AW_window *window){
52    window->hide();
53}
54
55/**
56 * CB wrapper for create_*_window calls to ensure that a window
57 * is only created once.
58 */
59
60#if defined(DEBUG)
61#define NOWINWARN() fputs("window factory did not create a window\n", stderr)
62#else
63#define NOWINWARN()
64#endif
65
66static AW_window *find_or_createAndRegisterWindow(CreateWindowCallback *windowMaker) {
67    typedef std::map<CreateWindowCallback, AW_window*> window_map;
68
69    static window_map     window;  // previously popped up windows
70    CreateWindowCallback& maker = *windowMaker;
71
72    if (window.find(maker) == window.end()) {
73        AW_window *made = maker(AW_root::SINGLETON);
74        if (!made) { NOWINWARN(); return NULL; }
75
76        window[maker] = made;
77    }
78    return window[maker];
79}
80
81void AW_window::popper(AW_window *, CreateWindowCallback *windowMaker) {
82    AW_window *toPopup = find_or_createAndRegisterWindow(windowMaker);
83    if (toPopup) toPopup->activate();
84}
85void AW_window::replacer(AW_window *caller, CreateWindowCallback *windowMaker) {
86    AW_window *toPopup = find_or_createAndRegisterWindow(windowMaker);
87    if (toPopup) {
88        toPopup->activate();
89        caller->hide();
90    }
91}
92void AW_window::destroyCreateWindowCallback(CreateWindowCallback *windowMaker) {
93    delete windowMaker;
94}
95
96
97void AW_window::label(const char *_label) {
98    freedup(_at->label_for_inputfield, _label);
99}
100
101// ----------------------------------------------------------------------
102// force-diff-sync 1927391236 (remove after merging back to trunk)
103// ----------------------------------------------------------------------
104
105void AW_window::get_window_size(int &width, int &height){
106    unsigned short hoffset = 0;
107    if (p_w->menu_bar[0]) XtVaGetValues(p_w->menu_bar[0], XmNheight, &hoffset, NULL);
108    width = _at->max_x_size;
109    height = hoffset + _at->max_y_size;
110}
111
112void AW_window::help_text(const char *id) {
113    //! set help text for next created button
114    delete _at->helptext_for_next_button; // @@@ delete/free mismatch
115    _at->helptext_for_next_button   = strdup(id);
116}
117
118void AW_window::highlight() {
119    //! make next created button default button
120    _at->highlight = true;
121}
122
123void AW_window::sens_mask(AW_active mask) {
124    //! Set up sensitivity mask for next widget (action)
125    aw_assert(legal_mask(mask));
126    _at->widget_mask = mask;
127}
128
129void AW_window::callback(const WindowCallback& wcb) {
130    /*!
131     * Register callback for the next action implicitly created
132     * when making a widget.
133     */
134    _callback = new AW_cb(this, wcb);
135}
136
137void AW_window::d_callback(const WindowCallback& wcb) {
138    /*!
139     * Register double click callback for the next action implicitly created
140     * when making a widget.
141     */
142    _d_callback = new AW_cb(this, wcb);
143}
144
145// -------------------------------------------------------------
146//      code used by scalers (common between motif and gtk)
147
148static float apply_ScalerType(float val, AW_ScalerType scalerType, bool inverse) {
149    float res = 0.0;
150
151    aw_assert(val>=0.0 && val<=1.0);
152
153    switch (scalerType) {
154        case AW_SCALER_LINEAR:
155            res = val;
156            break;
157
158        case AW_SCALER_EXP_LOWER:
159            if (inverse) res = pow(val, 1/3.0);
160            else         res = pow(val, 3.0);
161            break;
162
163        case AW_SCALER_EXP_UPPER:
164            res = 1.0-apply_ScalerType(1.0-val, AW_SCALER_EXP_LOWER, inverse);
165            break;
166
167        case AW_SCALER_EXP_BORDER:
168            inverse = !inverse;
169            // fall-through
170        case AW_SCALER_EXP_CENTER: {
171            AW_ScalerType subType = inverse ? AW_SCALER_EXP_UPPER : AW_SCALER_EXP_LOWER;
172            if      (val>0.5) res = (1+apply_ScalerType(2*val-1, subType, false))/2;
173            else if (val<0.5) res = (1-apply_ScalerType(1-2*val, subType, false))/2;
174            else              res = val;
175            break;
176        }
177    }
178
179    aw_assert(res>=0.0 && res<=1.0);
180
181    return res;
182}
183
184float AW_ScalerTransformer::scaler2awar(float scaler, AW_awar *awar) {
185    float amin        = awar->get_min();
186    float amax        = awar->get_max();
187    float modScaleRel = apply_ScalerType(scaler, type, false);
188    float aval        = amin + modScaleRel*(amax-amin);
189
190    return aval;
191}
192
193float AW_ScalerTransformer::awar2scaler(AW_awar *awar) {
194    float amin = awar->get_min();
195    float amax = awar->get_max();
196
197    float awarRel = 0.0;
198    switch (awar->variable_type) {
199        case AW_FLOAT:
200            awarRel = (awar->read_float()-amin) / (amax-amin);
201            break;
202
203        case AW_INT:
204            awarRel = (awar->read_int()-amin) / (amax-amin);
205            break;
206
207        default:
208            GBK_terminatef("Unsupported awar type %i in calculate_scaler_value", int(awar->variable_type));
209            break;
210    }
211
212    aw_assert(awarRel>=0.0 && awarRel<=1.0);
213
214    return apply_ScalerType(awarRel, type, true);
215}
216
217
218// ----------------------------------------------------------------------
219// force-diff-sync 7284637824 (remove after merging back to trunk)
220// ----------------------------------------------------------------------
221
222static unsigned timed_window_title_cb(AW_root*, char *title, AW_window *aw) {
223    aw->number_of_timed_title_changes--;
224    if (!aw->number_of_timed_title_changes) {
225        aw->set_window_title_intern(title);
226    }
227
228    delete title;
229    return 0; // do not recall
230}
231
232void AW_window::message(char *title, int ms) {
233    char *old_title = NULL;
234
235    number_of_timed_title_changes++;
236
237    old_title = strdup(window_name);
238
239    XtVaSetValues(p_w->shell, XmNtitle, title, NULL);
240
241    get_root()->add_timed_callback(ms, makeTimedCallback(timed_window_title_cb, old_title, this));
242}
243
244// ----------------------------------------------------------------------
245// force-diff-sync 1284672342939 (remove after merging back to trunk)
246// ----------------------------------------------------------------------
247
248// -------------------------
249//      Hotkey Checking
250
251#if defined(DEBUG)
252#define CHECK_DUPLICATED_MNEMONICS
253#endif
254
255#ifdef CHECK_DUPLICATED_MNEMONICS
256
257inline char oppositeCase(char c) {
258    return isupper(c) ? tolower(c) : toupper(c);
259}
260static void strcpy_overlapping(char *dest, char *src) {
261    int src_len = strlen(src);
262    memmove(dest, src, src_len+1);
263}
264static const char *possible_mnemonics(const char *used_mnemonics, bool top_level, const char *topic_name) {
265    static char *unused;
266    for (int fromTopic = 1; fromTopic>=0; --fromTopic) {
267        freedup(unused, fromTopic ? topic_name : "abcdefghijklmnopqrstuvwxyz");
268
269        for (int t = 0; unused[t]; ++t) {
270            bool remove = false;
271            if ((top_level && !isalpha(unused[t])) || !isalnum(unused[t])) { // remove useless chars
272                remove = true;
273            }
274            else {
275                char *dup = strchr(unused, unused[t]);
276                if (dup && (dup-unused)<t) { // remove duplicated chars
277                    remove = true;
278                }
279                else {
280                    dup = strchr(unused, oppositeCase(unused[t]));
281                    if (dup && (dup-unused)<t) { // char is duplicated with opposite case
282                        dup[0] = toupper(dup[0]); // prefer upper case
283                        remove = true;
284                    }
285                }
286            }
287            if (remove) {
288                strcpy_overlapping(unused+t, unused+t+1);
289                --t;
290            }
291        }
292
293        for (int t = 0; used_mnemonics[t]; ++t) {
294            char c = used_mnemonics[t]; // upper case!
295            char *u = strchr(unused, c);
296            if (u) strcpy_overlapping(u, u+1); // remove char
297            u = strchr(unused, tolower(c));
298            if (u) strcpy_overlapping(u, u+1); // remove char
299        }
300
301        if (unused[0]) {
302            if (!fromTopic) {
303                freeset(unused, GBS_global_string_copy("unused but not in topic: \"%s\"", unused));
304            }
305            break;
306        }
307    }
308    return unused;
309}
310
311class MnemonicScope : virtual Noncopyable {
312    typedef std::map<char,std::string> Char2Topic;
313
314    std::string    name;      // of menu or window
315    MnemonicScope *parent;
316    StrArray       requested; // topics lacking sufficient mnemonic
317    Char2Topic     accepted;  // accepted mnemonics (key = uppercase hotkey, value=topic)
318
319    void print_at_menu(FILE *out) {
320        if (parent) {
321            parent->print_at_menu(out);
322            fputc('|', out);
323        }
324        fputs(name.c_str(), out);
325    }
326    void print_at_location(FILE *out, const char *topic) {
327        fputs(" (", out);
328        print_at_menu(out);
329        fprintf(out, "|%s)\n", topic);
330    }
331
332    void requestPossibilities(const char *topic_name) {
333        // will be shown delayed (when menu closes)
334        if (requested.index_of(topic_name) == -1) { // avoid duplicates
335            requested.put(strdup(topic_name));
336        }
337    }
338
339    void showRequestedPossibilities() {
340        unsigned  size = accepted.size();
341        char     *used = new char[size+1];
342
343        int i = 0;
344        for (Char2Topic::iterator a = accepted.begin(); a != accepted.end(); ++a) {
345            used[i++] = a->first;
346        }
347        used[size] = 0;
348
349        for (i = 0; requested[i]; ++i) {
350            const char *possible = possible_mnemonics(used, !parent, requested[i]);
351            fprintf(stderr, "Warning: Possible mnemonics for '%s': '%s'\n", requested[i], possible);
352        }
353
354        delete [] used;
355    }
356
357    void warn_mnemonic(const char *topic_name, const char *mnemonic, const char *warning) {
358        fprintf(stderr, "Warning: mnemonic '%s' %s", mnemonic, warning);
359        print_at_location(stderr, topic_name);
360    }
361
362public:
363
364    MnemonicScope(const char *name_, MnemonicScope *parent_)
365        : name(name_),
366          parent(parent_)
367    {}
368
369    ~MnemonicScope() {
370        showRequestedPossibilities();
371    }
372
373    void add(const char *topic_name, const char *mnemonic);
374
375    MnemonicScope *get_parent() { return parent; }
376};
377
378static MnemonicScope *current_mscope = NULL;
379static MnemonicScope *help_mscope    = NULL;
380
381void MnemonicScope::add(const char *topic_name, const char *mnemonic) {
382    if (mnemonic && mnemonic[0] != 0) {
383        if (mnemonic[1]) { // longer than 1 char -> wrong
384            warn_mnemonic(topic_name, mnemonic, "is too long; only 1 character allowed");
385        }
386
387        if (AW_IS_IMAGEREF(topic_name)) {
388            if (mnemonic[0]) {
389                warn_mnemonic(topic_name, mnemonic, "is useless for graphical menu entry");
390            }
391        }
392        else if (!isalpha(mnemonic[0]) && !get_parent()) { // do not allow top-level numeric mnemonics
393            warn_mnemonic(topic_name, mnemonic, "is invalid (allowed: a-z)");
394            requestPossibilities(topic_name);
395        }
396        else if (!isalnum(mnemonic[0])) {
397            warn_mnemonic(topic_name, mnemonic, "is invalid (allowed: a-z and 0-9)");
398            requestPossibilities(topic_name);
399        }
400        else {
401            char *TOPIC_NAME = ARB_strupper(strdup(topic_name));
402            char  HOTKEY     = toupper(mnemonic[0]); // store hotkeys case-less (case does not matter when pressing the hotkey)
403
404            if (strchr(TOPIC_NAME, HOTKEY)) {  // occurs in menu text
405                Char2Topic::iterator found = accepted.find(HOTKEY);
406
407                if (found != accepted.end()) {
408                    warn_mnemonic(topic_name, mnemonic, "is used multiple times");
409                    requestPossibilities(topic_name);
410                    requestPossibilities(found->second.c_str()); // show possibilities for accepted duplicate
411                }
412                else {
413                    accepted[HOTKEY] = topic_name;
414
415                    if (!strchr(topic_name, mnemonic[0])) {
416                        char *warning = GBS_global_string_copy("has wrong case, use '%c'", HOTKEY == mnemonic[0] ? tolower(HOTKEY) : HOTKEY);
417                        warn_mnemonic(topic_name, mnemonic, warning);
418                        free(warning);
419                    }
420                }
421            }
422            else {
423                warn_mnemonic(topic_name, mnemonic, "is useless; does not occur in text");
424                requestPossibilities(topic_name);
425            }
426            free(TOPIC_NAME);
427        }
428    }
429    else {
430        if (!AW_IS_IMAGEREF(topic_name)) {
431            fputs("Warning: mnemonic is missing", stderr);
432            print_at_location(stderr, topic_name);
433            requestPossibilities(topic_name);
434        }
435    }
436}
437
438static void open_test_duplicate_mnemonics(const char *sub_menu_name, const char *mnemonic) {
439    aw_assert(current_mscope);
440    current_mscope->add(sub_menu_name, mnemonic);
441
442    MnemonicScope *prev = current_mscope;
443    current_mscope             = new MnemonicScope(sub_menu_name, prev);
444}
445
446static void close_test_duplicate_mnemonics() {
447    MnemonicScope *prev = current_mscope->get_parent();
448    delete current_mscope;
449    current_mscope = prev;
450}
451
452static void init_duplicate_mnemonic(const char *window_name) {
453    if (!current_mscope) {
454        current_mscope = new MnemonicScope(window_name, NULL);
455        help_mscope    = new MnemonicScope("<HELP>", current_mscope);
456    }
457    else {
458        while (current_mscope->get_parent()) {
459            close_test_duplicate_mnemonics();
460        }
461    }
462}
463
464static void test_duplicate_mnemonics(const char *topic_name, const char *mnemonic) {
465    aw_assert(current_mscope);
466    current_mscope->add(topic_name, mnemonic);
467}
468
469static void exit_duplicate_mnemonic() {
470    delete help_mscope; help_mscope = NULL;
471    while (current_mscope) close_test_duplicate_mnemonics();
472}
473
474
475#endif
476
477// ----------------------------------------------------------------------
478// force-diff-sync 9273192739 (remove after merging back to trunk)
479// ----------------------------------------------------------------------
480
481void AW_window::create_menu(AW_label name, const char *mnemonic, AW_active mask) {
482    aw_assert(legal_mask(mask));
483    p_w->menu_deep = 0;
484
485#ifdef CHECK_DUPLICATED_MNEMONICS
486    init_duplicate_mnemonic(window_name);
487#endif
488
489#if defined(DUMP_MENU_LIST)
490    dumpCloseAllSubMenus();
491#endif // DUMP_MENU_LIST
492    insert_sub_menu(name, mnemonic, mask);
493}
494
495void AW_window::close_sub_menu() {
496    /**
497     * Closes the currently open sub menu.
498     * If no menu is open this method will crash.
499     */
500#ifdef CHECK_DUPLICATED_MNEMONICS
501    close_test_duplicate_mnemonics();
502#endif
503#if defined(DUMP_MENU_LIST)
504    dumpCloseSubMenu();
505#endif // DUMP_MENU_LIST
506    if (p_w->menu_deep>0)
507        p_w->menu_deep--;
508}
509
510void AW_window::all_menus_created() const { // this is called by AW_window::show() (i.e. after all menus have been created)
511#if defined(DEBUG)
512    if (p_w->menu_deep>0) { // window had menu
513        aw_assert(p_w->menu_deep == 1);
514#ifdef CHECK_DUPLICATED_MNEMONICS
515        exit_duplicate_mnemonic(); // cleanup mnemonic check
516#endif
517    }
518#endif // DEBUG
519}
520
521// ----------------------------------------------------------------------
522// force-diff-sync 2939128467234 (remove after merging back to trunk)
523// ----------------------------------------------------------------------
524
525void AW_window::draw_line(int x1, int y1, int x2, int y2, int width, bool resize) {
526    aw_assert(xfig_data); // forgot to call load_xfig ?
527
528    xfig_data->add_line(x1, y1, x2, y2, width);
529
530    _at->max_x_size = std::max(_at->max_x_size, xfig_data->maxx - xfig_data->minx);
531    _at->max_y_size = std::max(_at->max_y_size, xfig_data->maxy - xfig_data->miny);
532
533    if (resize) {
534        recalc_size_atShow(AW_RESIZE_ANY);
535#if defined(ARB_MOTIF)
536        set_window_size(WIDER_THAN_SCREEN, HIGHER_THAN_SCREEN);
537#endif
538    }
539}
540
541AW_device_click *AW_window::get_click_device(AW_area area, int mousex, int mousey, int max_distance) {
542    AW_area_management *aram         = MAP_ARAM(area);
543    AW_device_click    *click_device = NULL;
544
545    if (aram) {
546        click_device = aram->get_click_device();
547        click_device->init_click(AW::Position(mousex, mousey), max_distance, AW_ALL_DEVICES);
548    }
549    return click_device;
550}
551
552AW_device *AW_window::get_device(AW_area area) { // @@@ rename to get_screen_device
553    AW_area_management *aram = MAP_ARAM(area);
554    arb_assert(aram);
555    return aram->get_screen_device();
556}
557
558void AW_window::get_event(AW_event *eventi) const {
559    *eventi = event;
560}
561
562AW_device_print *AW_window::get_print_device(AW_area area) {
563    AW_area_management *aram = MAP_ARAM(area);
564    return aram ? aram->get_print_device() : NULL;
565}
566
567AW_device_size *AW_window::get_size_device(AW_area area) {
568    AW_area_management *aram = MAP_ARAM(area);
569    if (!aram) return NULL;
570
571    AW_device_size *size_device = aram->get_size_device();
572    if (size_device) {
573        size_device->restart_tracking();
574        size_device->reset(); // @@@ hm
575    }
576    return size_device;
577}
578
579
580void AW_window::insert_help_topic(const char *labeli, 
581                                  const char *mnemonic, const char *helpText,
582                                  AW_active mask, const WindowCallback& cb) {
583    aw_assert(legal_mask(mask));
584    Widget button;
585
586#ifdef CHECK_DUPLICATED_MNEMONICS
587    if (!current_mscope) init_duplicate_mnemonic(window_name);
588    MnemonicScope *tmp = current_mscope;
589    current_mscope     = help_mscope;
590    test_duplicate_mnemonics(labeli, mnemonic);
591    current_mscope     = tmp;
592#endif
593
594    // insert one help-sub-menu-entry
595    button = XtVaCreateManagedWidget("", xmPushButtonWidgetClass,
596                                     p_w->help_pull_down,
597                                     RES_CONVERT(XmNlabelString, labeli),
598                                     RES_CONVERT(XmNmnemonic, mnemonic), NULL);
599    XtAddCallback(button, XmNactivateCallback,
600                  (XtCallbackProc) AW_server_callback,
601                  (XtPointer) new AW_cb(this, cb, helpText));
602
603    root->make_sensitive(button, mask);
604}
605
606void AW_window::insert_menu_topic(const char *topic_id, const char *labeltext,
607                                  const char *mnemonic, const char *helpText,
608                                  AW_active mask, const WindowCallback& wcb) {
609    aw_assert(legal_mask(mask));
610    Widget button;
611
612    TuneBackground(p_w->menu_bar[p_w->menu_deep], TUNE_MENUTOPIC); // set background color for normal menu topics
613
614#if defined(DUMP_MENU_LIST)
615    dumpMenuEntry(name);
616#endif // DUMP_MENU_LIST
617
618#ifdef CHECK_DUPLICATED_MNEMONICS
619    test_duplicate_mnemonics(labeltext, mnemonic);
620#endif
621
622    Label topiclabel(labeltext, this);
623    if (mnemonic && *mnemonic && strchr(labeltext, mnemonic[0])) {
624        // create one sub-menu-point
625        button = XtVaCreateManagedWidget("", xmPushButtonWidgetClass,
626                                         p_w->menu_bar[p_w->menu_deep],
627                                         RES_LABEL_CONVERT(topiclabel),
628                                         RES_CONVERT(XmNmnemonic, mnemonic),
629                                         XmNbackground, _at->background_color, NULL);
630    }
631    else {
632        button = XtVaCreateManagedWidget("",
633                                         xmPushButtonWidgetClass,
634                                         p_w->menu_bar[p_w->menu_deep],
635                                         RES_LABEL_CONVERT(topiclabel),
636                                         XmNbackground, _at->background_color,
637                                         NULL);
638    }
639
640    AW_label_in_awar_list(this, button, labeltext);
641    AW_cb *cbs = new AW_cb(this, wcb, helpText);
642    XtAddCallback(button, XmNactivateCallback,
643                  (XtCallbackProc) AW_server_callback,
644                  (XtPointer) cbs);
645
646#if defined(DEVEL_RALF) // wanted version
647    aw_assert(topic_id);
648#else // !defined(DEVEL_RALF)
649    if (!topic_id) topic_id = labeltext;
650#endif
651    cbs->id = strdup(topic_id);
652    root->define_remote_command(cbs);
653    root->make_sensitive(button, mask);
654}
655
656// ----------------------------------------------------------------------
657// force-diff-sync 824638723647 (remove after merging back to trunk)
658// ----------------------------------------------------------------------
659
660void AW_window::insert_sub_menu(const char *labeli, const char *mnemonic, AW_active mask){
661    aw_assert(legal_mask(mask));
662    Widget shell, Label;
663
664    TuneBackground(p_w->menu_bar[p_w->menu_deep], TUNE_SUBMENU); // set background color for submenus
665    // (Note: This must even be called if TUNE_SUBMENU is 0!
666    //        Otherwise several submenus get the TUNE_MENUTOPIC color)
667
668#if defined(DUMP_MENU_LIST)
669    dumpOpenSubMenu(name);
670#endif // DUMP_MENU_LIST
671
672#ifdef CHECK_DUPLICATED_MNEMONICS
673    open_test_duplicate_mnemonics(labeli, mnemonic);
674#endif
675
676    // create shell for Pull-Down
677    shell = XtVaCreatePopupShell("menu_shell", xmMenuShellWidgetClass,
678                                 p_w->menu_bar[p_w->menu_deep],
679                                 XmNwidth, 1,
680                                 XmNheight, 1,
681                                 XmNallowShellResize, true,
682                                 XmNoverrideRedirect, true,
683                                 NULL);
684
685    // create row column in Pull-Down shell
686
687    p_w->menu_bar[p_w->menu_deep+1] = XtVaCreateWidget("menu_row_column",
688                                                       xmRowColumnWidgetClass, shell,
689                                                       XmNrowColumnType, XmMENU_PULLDOWN,
690                                                       XmNtearOffModel, XmTEAR_OFF_ENABLED,
691                                                       NULL);
692
693    // create label in menu bar
694    if (mnemonic && *mnemonic && strchr(labeli, mnemonic[0])) {
695        // if mnemonic is "" -> Cannot convert string "" to type KeySym
696        Label = XtVaCreateManagedWidget("menu1_top_b1",
697                                        xmCascadeButtonWidgetClass, p_w->menu_bar[p_w->menu_deep],
698                                        RES_CONVERT(XmNlabelString, labeli),
699                                        RES_CONVERT(XmNmnemonic, mnemonic),
700                                        XmNsubMenuId, p_w->menu_bar[p_w->menu_deep+1],
701                                        XmNbackground, _at->background_color, NULL);
702    }
703    else {
704        Label = XtVaCreateManagedWidget("menu1_top_b1",
705                                        xmCascadeButtonWidgetClass,
706                                        p_w->menu_bar[p_w->menu_deep],
707                                        RES_CONVERT(XmNlabelString, labeli),
708                                        XmNsubMenuId, p_w->menu_bar[p_w->menu_deep+1],
709                                        XmNbackground, _at->background_color,
710                                        NULL);
711    }
712
713    if (p_w->menu_deep < AW_MAX_MENU_DEEP-1) p_w->menu_deep++;
714
715    root->make_sensitive(Label, mask);
716}
717
718static void AW_xfigCB_info_area(AW_window *aww, AW_xfig *xfig) {
719    AW_device *device = aww->get_device(AW_INFO_AREA);
720    device->reset();
721
722    if (aww->get_root()->color_mode == 0) { // mono colr
723        device->clear(-1);
724    }
725    device->set_offset(AW::Vector(-xfig->minx, -xfig->miny));
726
727    xfig->print(device);
728}
729
730void AW_window::get_font_size(int& width, int& height) {
731    width  = get_root()->font_width;
732    height = get_root()->font_height;
733}
734
735// ----------------------------------------------------------------------
736// force-diff-sync 264782364273 (remove after merging back to trunk)
737// ----------------------------------------------------------------------
738
739void AW_window::load_xfig(const char *file, bool resize /*= true*/) {
740    int width, height;
741    get_font_size(width, height);
742
743    if (file)   xfig_data = new AW_xfig(file, width, height);
744    else        xfig_data = new AW_xfig(width, height); // create an empty xfig
745
746    xfig_data->create_gcs(get_device(AW_INFO_AREA), get_root()->color_mode ? 8 : 1);
747
748    // @@@ move into AW_at::set_xfig
749    int xsize = xfig_data->maxx - xfig_data->minx;
750    int ysize = xfig_data->maxy - xfig_data->miny;
751    if (xsize>_at->max_x_size) _at->max_x_size = xsize;
752    if (ysize>_at->max_y_size) _at->max_y_size = ysize;
753
754    if (resize) {
755        recalc_size_atShow(AW_RESIZE_ANY);
756#if defined(ARB_MOTIF)
757        set_window_size(WIDER_THAN_SCREEN, HIGHER_THAN_SCREEN);
758#else
759        // @@@ should not be needed in gtk, as soon as recalc_size_atShow has proper effect (see #377)
760        // @@@ This is the last remaining use in gtk! Remove if removed here.
761        set_window_size(_at->max_x_size, _at->max_y_size);
762#endif
763    }
764
765    set_expose_callback(AW_INFO_AREA, makeWindowCallback(AW_xfigCB_info_area, xfig_data));
766}
767
768/**
769 * Construct window-local id.
770 * Prefixes @param id with AW_window::window_defaults_name + "/"
771 */
772const char *AW_window::local_id(const char *id) const {
773    static char *last_local_id = 0;
774    freeset(last_local_id, GBS_global_string_copy("%s/%s", get_window_id(), id));
775    return last_local_id;
776}
777
778void AW_window::sep______________() {
779    //! insert a separator into the currently open menu
780    XtVaCreateManagedWidget("", xmSeparatorWidgetClass,
781                            p_w->menu_bar[p_w->menu_deep],
782                            NULL);
783}
784
785/**
786 * Registers @param wcb as expose callback.
787 * Called whenever the @param area receives an expose event.
788 * This is where any drawing should be handled.
789 */
790void AW_window::set_expose_callback(AW_area area, const WindowCallback& wcb) {
791    AW_area_management *aram = MAP_ARAM(area);
792    if (aram) aram->set_expose_callback(this, wcb);
793}
794
795static void AW_focusCB(Widget /*wgt*/, XtPointer cl_aww, XEvent*, Boolean*) {
796    AW_window *aww = (AW_window*)cl_aww;
797    aww->run_focus_callback();
798}
799
800/**
801 * Registers a focus callback.
802 */
803void AW_window::set_focus_callback(const WindowCallback& wcb) {
804    if (!focus_cb) {
805        XtAddEventHandler(MIDDLE_WIDGET, EnterWindowMask, FALSE, AW_focusCB, (XtPointer) this);
806    }
807    if (!focus_cb || !focus_cb->contains((AnyWinCB)wcb.callee())) {
808        focus_cb = new AW_cb(this, wcb, 0, focus_cb);
809    }
810}
811
812/**
813 * Registers callback to be executed after the window is shown.
814 * Called multiple times if a show() follows a hide().
815 */
816void AW_window::set_popup_callback(const WindowCallback& wcb) {
817    p_w->popup_cb = new AW_cb(this, wcb, 0, p_w->popup_cb);
818}
819
820void AW_window::set_info_area_height(int h) {
821    XtVaSetValues(INFO_WIDGET, XmNheight, h, NULL);
822    XtVaSetValues(p_w->frame, XmNtopOffset, h, NULL);
823}
824
825void AW_window::set_bottom_area_height(int h) {
826    XtVaSetValues(BOTTOM_WIDGET, XmNheight, h, NULL);
827    XtVaSetValues(p_w->scroll_bar_horizontal, XmNbottomOffset, (int)h, NULL);
828}
829
830void AW_window::set_input_callback(AW_area area, const WindowCallback& wcb) {
831    AW_area_management *aram = MAP_ARAM(area);
832    if (aram) aram->set_input_callback(this, wcb);
833}
834
835void AW_window::set_motion_callback(AW_area area, const WindowCallback& wcb) {
836    AW_area_management *aram = MAP_ARAM(area);
837    if (aram) aram->set_motion_callback(this, wcb);
838}
839
840void AW_window::set_resize_callback(AW_area area, const WindowCallback& wcb) {
841    AW_area_management *aram = MAP_ARAM(area);
842    if (aram) aram->set_resize_callback(this, wcb);
843}
844
845// SCROLL BAR STUFF
846
847void AW_window::tell_scrolled_picture_size(AW_screen_area rectangle) {
848    picture->l = rectangle.l;
849    picture->r = rectangle.r;
850    picture->t = rectangle.t;
851    picture->b = rectangle.b;
852}
853
854void AW_window::tell_scrolled_picture_size(AW_world rectangle) {
855    picture->l = (int)rectangle.l;
856    picture->r = (int)rectangle.r;
857    picture->t = (int)rectangle.t;
858    picture->b = (int)rectangle.b;
859}
860
861AW_pos AW_window::get_scrolled_picture_width() const {
862    return (picture->r - picture->l);
863}
864
865AW_pos AW_window::get_scrolled_picture_height() const {
866    return (picture->b - picture->t);
867}
868
869void AW_window::reset_scrolled_picture_size() {
870    picture->l = 0;
871    picture->r = 0;
872    picture->t = 0;
873    picture->b = 0;
874}
875
876void AW_window::set_vertical_scrollbar_top_indent(int indent) {
877    XtVaSetValues(p_w->scroll_bar_vertical, XmNtopOffset, (int)indent, NULL);
878    top_indent_of_vertical_scrollbar = indent;
879}
880
881void AW_window::set_horizontal_scrollbar_left_indent(int indent) {
882    XtVaSetValues(p_w->scroll_bar_horizontal, XmNleftOffset, (int)indent, NULL);
883    left_indent_of_horizontal_scrollbar = indent;
884}
885
886void AW_window::_get_area_size(AW_area area, AW_screen_area *square) {
887    AW_area_management *aram = MAP_ARAM(area);
888    *square = aram->get_common()->get_screen();
889}
890
891void AW_window::get_scrollarea_size(AW_screen_area *square) {
892    _get_area_size(AW_MIDDLE_AREA, square);
893    square->r -= left_indent_of_horizontal_scrollbar;
894    square->b -= top_indent_of_vertical_scrollbar;
895}
896
897void AW_window::calculate_scrollbars() {
898    AW_screen_area scrollArea;
899    get_scrollarea_size(&scrollArea);
900
901    // HORIZONTAL
902    {
903        int slider_max = (int)get_scrolled_picture_width();
904        if (slider_max <1) {
905            slider_max = 1;
906            XtVaSetValues(p_w->scroll_bar_horizontal, XmNsliderSize, 1, NULL);
907        }
908
909        bool use_horizontal_bar     = true;
910        int  slider_size_horizontal = scrollArea.r;
911
912        if (slider_size_horizontal < 1) slider_size_horizontal = 1; // ist der slider zu klein (<1) ?
913        if (slider_size_horizontal > slider_max) { // Schirm groesser als Bild
914            slider_size_horizontal = slider_max; // slider nimmt ganze laenge ein
915            XtVaSetValues(p_w->scroll_bar_horizontal, XmNvalue, 0, NULL); // slider ganz links setzen
916            use_horizontal_bar = false; // kein horizontaler slider mehr
917        }
918
919        // check wether XmNValue is to big
920        int position_of_slider;
921        XtVaGetValues(p_w->scroll_bar_horizontal, XmNvalue, &position_of_slider, NULL);
922        if (position_of_slider > (slider_max-slider_size_horizontal)) { // steht der slider fuer slidergroesse zu rechts ?
923            position_of_slider = slider_max-slider_size_horizontal; // -1 ? vielleicht !
924            if (position_of_slider < 0) position_of_slider = 0;
925            XtVaSetValues(p_w->scroll_bar_horizontal, XmNvalue, position_of_slider, NULL);
926        }
927        // Anpassung fuer resize, wenn unbeschriebener Bereich vergroessert wird
928        int max_slider_pos = (int)(get_scrolled_picture_width() - scrollArea.r);
929        if (slider_pos_horizontal>max_slider_pos) {
930            slider_pos_horizontal = use_horizontal_bar ? max_slider_pos : 0;
931        }
932
933        XtVaSetValues(p_w->scroll_bar_horizontal, XmNsliderSize, 1, NULL);
934        XtVaSetValues(p_w->scroll_bar_horizontal, XmNmaximum, slider_max, NULL);
935        XtVaSetValues(p_w->scroll_bar_horizontal, XmNsliderSize, slider_size_horizontal, NULL);
936
937        update_scrollbar_settings_from_awars(AW_HORIZONTAL);
938    }
939
940    // VERTICAL
941    {
942        int slider_max = (int)get_scrolled_picture_height();
943        if (slider_max <1) {
944            slider_max = 1;
945            XtVaSetValues(p_w->scroll_bar_vertical, XmNsliderSize, 1, NULL);
946        }
947
948        bool use_vertical_bar     = true;
949        int  slider_size_vertical = scrollArea.b;
950
951        if (slider_size_vertical < 1) slider_size_vertical = 1;
952        if (slider_size_vertical > slider_max) {
953            slider_size_vertical = slider_max;
954            XtVaSetValues(p_w->scroll_bar_vertical, XmNvalue, 0, NULL);
955            use_vertical_bar = false;
956        }
957
958        // check wether XmNValue is to big
959        int position_of_slider;
960        XtVaGetValues(p_w->scroll_bar_vertical, XmNvalue, &position_of_slider, NULL);
961        if (position_of_slider > (slider_max-slider_size_vertical)) {
962            position_of_slider = slider_max-slider_size_vertical; // -1 ? vielleicht !
963            if (position_of_slider < 0) position_of_slider = 0;
964            XtVaSetValues(p_w->scroll_bar_vertical, XmNvalue, position_of_slider, NULL);
965        }
966        // Anpassung fuer resize, wenn unbeschriebener Bereich vergroessert wird
967        int max_slider_pos = (int)(get_scrolled_picture_height() - scrollArea.b);
968        if (slider_pos_vertical>max_slider_pos) {
969            slider_pos_vertical = use_vertical_bar ? max_slider_pos : 0;
970        }
971
972        XtVaSetValues(p_w->scroll_bar_vertical, XmNsliderSize, 1, NULL);
973        XtVaSetValues(p_w->scroll_bar_vertical, XmNmaximum, slider_max, NULL);
974        XtVaSetValues(p_w->scroll_bar_vertical, XmNsliderSize, slider_size_vertical, NULL);
975
976        update_scrollbar_settings_from_awars(AW_VERTICAL);
977    }
978}
979
980// ----------------------------------------------------------------------
981// force-diff-sync 82346723846 (remove after merging back to trunk)
982// ----------------------------------------------------------------------
983
984static void horizontal_scrollbar_redefinition_cb(AW_root*, AW_window *aw) {
985    aw->update_scrollbar_settings_from_awars(AW_HORIZONTAL);
986}
987
988static void vertical_scrollbar_redefinition_cb(AW_root*, AW_window *aw) {
989    aw->update_scrollbar_settings_from_awars(AW_VERTICAL);
990}
991
992const char *AW_window::window_local_awarname(const char *localname, bool tmp) {
993    CONSTEXPR int MAXNAMELEN = 200;
994    static char   buffer[MAXNAMELEN];
995    return GBS_global_string_to_buffer(buffer, MAXNAMELEN,
996                                       tmp ? "tmp/window/%s/%s" : "window/%s/%s",
997                                       window_defaults_name, localname);
998    // (see also aw_size_awar_name)
999}
1000
1001AW_awar *AW_window::window_local_awar(const char *localname, bool tmp) {
1002    return get_root()->awar(window_local_awarname(localname, tmp));
1003}
1004
1005void AW_window::create_window_variables() {
1006    RootCallback hor_src = makeRootCallback(horizontal_scrollbar_redefinition_cb, this);
1007    RootCallback ver_src = makeRootCallback(vertical_scrollbar_redefinition_cb, this);
1008
1009    get_root()->awar_int(window_local_awarname("horizontal_page_increment"), 50)->add_callback(hor_src);
1010    get_root()->awar_int(window_local_awarname("vertical_page_increment"),   50)->add_callback(ver_src);
1011    get_root()->awar_int(window_local_awarname("scroll_width_horizontal"),    9)->add_callback(hor_src);
1012    get_root()->awar_int(window_local_awarname("scroll_width_vertical"),     20)->add_callback(ver_src);
1013    get_root()->awar_int(window_local_awarname("scroll_delay_horizontal"),   20)->add_callback(hor_src);
1014    get_root()->awar_int(window_local_awarname("scroll_delay_vertical"),     20)->add_callback(ver_src);
1015}
1016
1017void AW_window::set_vertical_scrollbar_position(int position){
1018#if defined(DEBUG) && 0
1019    fprintf(stderr, "set_vertical_scrollbar_position to %i\n", position);
1020#endif
1021    // @@@ test and constrain against limits
1022    slider_pos_vertical = position;
1023    XtVaSetValues(p_w->scroll_bar_vertical, XmNvalue, position, NULL);
1024}
1025
1026void AW_window::set_horizontal_scrollbar_position(int position) {
1027#if defined(DEBUG) && 0
1028    fprintf(stderr, "set_horizontal_scrollbar_position to %i\n", position);
1029#endif
1030    // @@@ test and constrain against limits
1031    slider_pos_horizontal = position;
1032    XtVaSetValues(p_w->scroll_bar_horizontal, XmNvalue, position, NULL);
1033}
1034
1035static void value_changed_scroll_bar_vertical(Widget /*wgt*/, XtPointer aw_cb_struct, XtPointer call_data) {
1036    XmScrollBarCallbackStruct *sbcbs = (XmScrollBarCallbackStruct *)call_data;
1037    AW_cb *cbs = (AW_cb *) aw_cb_struct;
1038    cbs->aw->slider_pos_vertical = sbcbs->value; // setzt Scrollwerte im AW_window
1039    cbs->run_callbacks();
1040}
1041static void value_changed_scroll_bar_horizontal(Widget /*wgt*/, XtPointer aw_cb_struct, XtPointer call_data) {
1042    XmScrollBarCallbackStruct *sbcbs = (XmScrollBarCallbackStruct *)call_data;
1043    AW_cb *cbs = (AW_cb *) aw_cb_struct;
1044    (cbs->aw)->slider_pos_horizontal = sbcbs->value; // setzt Scrollwerte im AW_window
1045    cbs->run_callbacks();
1046}
1047
1048static void drag_scroll_bar_vertical(Widget /*wgt*/, XtPointer aw_cb_struct, XtPointer call_data) {
1049    XmScrollBarCallbackStruct *sbcbs = (XmScrollBarCallbackStruct *)call_data;
1050    AW_cb *cbs = (AW_cb *) aw_cb_struct;
1051    cbs->aw->slider_pos_vertical = sbcbs->value; // setzt Scrollwerte im AW_window
1052    cbs->run_callbacks();
1053}
1054static void drag_scroll_bar_horizontal(Widget /*wgt*/, XtPointer aw_cb_struct, XtPointer call_data) {
1055    XmScrollBarCallbackStruct *sbcbs = (XmScrollBarCallbackStruct *)call_data;
1056    AW_cb *cbs = (AW_cb *) aw_cb_struct;
1057    (cbs->aw)->slider_pos_horizontal = sbcbs->value; // setzt Scrollwerte im AW_window
1058    cbs->run_callbacks();
1059}
1060
1061void AW_window::set_vertical_change_callback(const WindowCallback& wcb) {
1062    XtAddCallback(p_w->scroll_bar_vertical, XmNvalueChangedCallback,
1063            (XtCallbackProc) value_changed_scroll_bar_vertical,
1064            (XtPointer) new AW_cb(this, wcb, ""));
1065    XtAddCallback(p_w->scroll_bar_vertical, XmNdragCallback,
1066            (XtCallbackProc) drag_scroll_bar_vertical,
1067            (XtPointer) new AW_cb(this, wcb, ""));
1068
1069    XtAddCallback(p_w->scroll_bar_vertical, XmNpageIncrementCallback,
1070            (XtCallbackProc) drag_scroll_bar_vertical,
1071            (XtPointer) new AW_cb(this, wcb, ""));
1072    XtAddCallback(p_w->scroll_bar_vertical, XmNpageDecrementCallback,
1073            (XtCallbackProc) drag_scroll_bar_vertical,
1074            (XtPointer) new AW_cb(this, wcb, ""));
1075}
1076
1077void AW_window::set_horizontal_change_callback(const WindowCallback& wcb) {
1078    XtAddCallback(p_w->scroll_bar_horizontal, XmNvalueChangedCallback,
1079                  (XtCallbackProc) value_changed_scroll_bar_horizontal,
1080                  (XtPointer) new AW_cb(this, wcb, ""));
1081    XtAddCallback(p_w->scroll_bar_horizontal, XmNdragCallback,
1082            (XtCallbackProc) drag_scroll_bar_horizontal,
1083            (XtPointer) new AW_cb(this, wcb, ""));
1084}
1085
1086// END SCROLLBAR STUFF
1087
1088
1089void AW_window::set_window_size(int width, int height) {
1090    XtVaSetValues(p_w->shell, XmNwidth, (int)width, XmNheight, (int)height, NULL);
1091}
1092
1093void AW_window::set_window_title_intern(char *title) {
1094    XtVaSetValues(p_w->shell, XmNtitle, title, NULL);
1095}
1096
1097void AW_window::set_window_title(const char *title){
1098    XtVaSetValues(p_w->shell, XmNtitle, title, NULL);
1099    freedup(window_name, title);
1100}
1101
1102const char* AW_window::get_window_title() const {
1103    return window_name;
1104}
1105
1106void AW_window::shadow_width(int shadow_thickness) {
1107    _at->shadow_thickness = shadow_thickness;
1108}
1109
1110#if defined(ARB_MOTIF)
1111void AW_window::button_height(int height) {
1112    _at->height_of_buttons = height>1 ? height : 0;
1113}
1114#endif
1115
1116// ----------------------------------------------------------------------
1117// force-diff-sync 874687234237 (remove after merging back to trunk)
1118// ----------------------------------------------------------------------
1119
1120void AW_window::window_fit() {
1121    int width, height;
1122    get_window_size(width, height);
1123    set_window_size(width, height);
1124}
1125
1126AW_window::AW_window()
1127    : recalc_size_at_show(AW_KEEP_SIZE),
1128      recalc_pos_at_show(AW_KEEP_POS),
1129      hide_cb(NULL),
1130      expose_callback_added(false),
1131      focus_cb(NULL),
1132      xfig_data(NULL),
1133      _at(new AW_at),
1134      left_indent_of_horizontal_scrollbar(0),
1135      top_indent_of_vertical_scrollbar(0),
1136      root(NULL),
1137      click_time(0),
1138      color_table_size(0),
1139      color_table(NULL),
1140      number_of_timed_title_changes(0),
1141      p_w(new AW_window_Motif),
1142      _callback(NULL),
1143      _d_callback(NULL),
1144      window_name(NULL),
1145      window_defaults_name(NULL),
1146      slider_pos_vertical(0),
1147      slider_pos_horizontal(0),
1148      window_is_shown(false),
1149      picture(new AW_screen_area)
1150{
1151    reset_scrolled_picture_size();
1152}
1153
1154AW_window::~AW_window() {
1155    delete picture;
1156    delete p_w;
1157}
1158
1159#if defined(DEBUG)
1160// #define DUMP_MENU_LIST          // this should NOT be defined normally (if defined, every window writes all menu-entries to stdout)
1161#endif // DEBUG
1162#if defined(DUMP_MENU_LIST)
1163
1164static char *window_name = 0;
1165static char *sub_menu = 0;
1166
1167static void initMenuListing(const char *win_name) {
1168    aw_assert(win_name);
1169
1170    freedup(window_name, win_name);
1171    freenull(sub_menu);
1172
1173    printf("---------------------------------------- list of menus for '%s'\n", window_name);
1174}
1175
1176static void dumpMenuEntry(const char *entry) {
1177    aw_assert(window_name);
1178    if (sub_menu) {
1179        printf("'%s/%s/%s'\n", window_name, sub_menu, entry);
1180    }
1181    else {
1182        printf("'%s/%s'\n", window_name, entry);
1183    }
1184}
1185
1186static void dumpOpenSubMenu(const char *sub_name) {
1187    aw_assert(sub_name);
1188
1189    dumpMenuEntry(sub_name); // dump the menu itself
1190
1191    if (sub_menu) freeset(sub_menu, GBS_global_string_copy("%s/%s", sub_menu, sub_name));
1192    else sub_menu = strdup(sub_name);
1193}
1194
1195static void dumpCloseSubMenu() {
1196    aw_assert(sub_menu);
1197    char *lslash = strrchr(sub_menu, '/');
1198    if (lslash) {
1199        lslash[0] = 0;
1200    }
1201    else freenull(sub_menu);
1202}
1203
1204static void dumpCloseAllSubMenus() {
1205    freenull(sub_menu);
1206}
1207
1208#endif // DUMP_MENU_LIST
1209
1210AW_window_menu_modes::AW_window_menu_modes() : AW_window_menu_modes_private(NULL) {}
1211AW_window_menu_modes::~AW_window_menu_modes() {}
1212
1213AW_window_menu::AW_window_menu() {}
1214AW_window_menu::~AW_window_menu() {}
1215
1216AW_window_simple::AW_window_simple() {}
1217AW_window_simple::~AW_window_simple() {}
1218
1219AW_window_simple_menu::AW_window_simple_menu() {}
1220AW_window_simple_menu::~AW_window_simple_menu() {}
1221
1222AW_window_message::AW_window_message() {}
1223AW_window_message::~AW_window_message() {}
1224
1225#define LAYOUT_AWAR_ROOT "window/windows"
1226#define BUFSIZE 256
1227static char aw_size_awar_name_buffer[BUFSIZE];
1228static const char *aw_size_awar_name(AW_window *aww, const char *sub_entry) {
1229#if defined(DEBUG)
1230    int size =
1231#endif // DEBUG
1232            sprintf(aw_size_awar_name_buffer, LAYOUT_AWAR_ROOT "/%s/%s",
1233                    aww->window_defaults_name, sub_entry);
1234#if defined(DEBUG)
1235    aw_assert(size < BUFSIZE);
1236#endif // DEBUG
1237    return aw_size_awar_name_buffer;
1238    // (see also AW_window::window_local_awarname)
1239}
1240#undef BUFSIZE
1241
1242#define aw_awar_name_posx(aww)   aw_size_awar_name((aww), "posx")
1243#define aw_awar_name_posy(aww)   aw_size_awar_name((aww), "posy")
1244#define aw_awar_name_width(aww)  aw_size_awar_name((aww), "width")
1245#define aw_awar_name_height(aww) aw_size_awar_name((aww), "height")
1246
1247void AW_window::create_user_geometry_awars(int posx, int posy, int width, int height) {
1248    get_root()->awar_int(aw_awar_name_posx(this), posx);
1249    get_root()->awar_int(aw_awar_name_posy(this), posy);
1250    get_root()->awar_int(aw_awar_name_width(this), width);
1251    get_root()->awar_int(aw_awar_name_height(this), height);
1252}
1253
1254
1255void AW_window::store_size_in_awars(int width, int height) {
1256    get_root()->awar(aw_awar_name_width(this))->write_int(width);
1257    get_root()->awar(aw_awar_name_height(this))->write_int(height);
1258}
1259
1260void AW_window::get_size_from_awars(int& width, int& height) {
1261    width  = get_root()->awar(aw_awar_name_width(this))->read_int();
1262    height = get_root()->awar(aw_awar_name_height(this))->read_int();
1263}
1264
1265void AW_window::store_pos_in_awars(int posx, int posy) {
1266    get_root()->awar(aw_awar_name_posx(this))->write_int(posx);
1267    get_root()->awar(aw_awar_name_posy(this))->write_int(posy);
1268}
1269
1270void AW_window::get_pos_from_awars(int& posx, int& posy) {
1271    posx = get_root()->awar(aw_awar_name_posx(this))->read_int();
1272    posy = get_root()->awar(aw_awar_name_posy(this))->read_int();
1273}
1274
1275void AW_window::reset_geometry_awars() {
1276    AW_root *awr = get_root();
1277
1278    ASSERT_NO_ERROR(awr->awar(aw_awar_name_posx(this))  ->reset_to_default());
1279    ASSERT_NO_ERROR(awr->awar(aw_awar_name_posy(this))  ->reset_to_default());
1280    ASSERT_NO_ERROR(awr->awar(aw_awar_name_width(this)) ->reset_to_default());
1281    ASSERT_NO_ERROR(awr->awar(aw_awar_name_height(this))->reset_to_default());
1282
1283    recalc_pos_atShow(AW_REPOS_TO_MOUSE_ONCE);
1284    recalc_size_atShow(AW_RESIZE_ANY);
1285}
1286
1287#undef aw_awar_name_posx
1288#undef aw_awar_name_posy
1289#undef aw_awar_name_width
1290#undef aw_awar_name_height
1291
1292static void aw_onExpose_calc_WM_offsets(AW_window *aww);
1293static unsigned aw_calc_WM_offsets_delayed(AW_root *, AW_window*aww) { aw_onExpose_calc_WM_offsets(aww); return 0; }
1294
1295static void aw_onExpose_calc_WM_offsets(AW_window *aww) {
1296    AW_window_Motif *motif = p_aww(aww);
1297
1298    int posx,  posy;  aww->get_window_content_pos(posx, posy);
1299
1300    bool knows_window_position = posx != 0 || posy != 0;
1301
1302    if (!knows_window_position) { // oops - motif has no idea where the window has been placed
1303        // assume positions stored in awars are correct and use them.
1304        // This works around problems with unclickable GUI-elements when running on 'Unity'
1305
1306        int oposx, oposy; aww->get_pos_from_awars(oposx, oposy);
1307        aww->set_window_frame_pos(oposx, oposy);
1308
1309        if (!motif->knows_WM_offset()) {
1310            aww->get_root()->add_timed_callback(100, makeTimedCallback(aw_calc_WM_offsets_delayed, aww));
1311        }
1312    }
1313    else if (!motif->knows_WM_offset()) {
1314        int oposx, oposy; aww->get_pos_from_awars(oposx, oposy);
1315
1316        // calculate offset
1317        int left = posx-oposx;
1318        int top  = posy-oposy;
1319
1320        if (top == 0 || left == 0)  { // invalid frame size
1321            if (motif->WM_left_offset == 0) {
1322                motif->WM_left_offset = 1; // hack: unused yet, use as flag to avoid endless repeats
1323#if defined(DEBUG)
1324                fprintf(stderr, "aw_onExpose_calc_WM_offsets: failed to detect framesize (shift window 1 pixel and retry)\n");
1325#endif
1326                oposx = oposx>10 ? oposx-1 : oposx+1;
1327                oposy = oposy>10 ? oposy-1 : oposy+1;
1328
1329                aww->set_window_frame_pos(oposx, oposy);
1330                aww->store_pos_in_awars(oposx, oposy);
1331
1332                aww->get_root()->add_timed_callback(500, makeTimedCallback(aw_calc_WM_offsets_delayed, aww));
1333                return;
1334            }
1335            else {
1336                // use maximum seen frame size
1337                top  = AW_window_Motif::WM_max_top_offset;
1338                left = AW_window_Motif::WM_max_left_offset;
1339
1340                if (top == 0 || left == 0) { // still invalid -> retry later
1341                    aww->get_root()->add_timed_callback(10000, makeTimedCallback(aw_calc_WM_offsets_delayed, aww));
1342                    return;
1343                }
1344            }
1345        }
1346        motif->WM_top_offset  = top;
1347        motif->WM_left_offset = left;
1348
1349        // remember maximum seen offsets
1350        AW_window_Motif::WM_max_top_offset  = std::max(AW_window_Motif::WM_max_top_offset,  motif->WM_top_offset);
1351        AW_window_Motif::WM_max_left_offset = std::max(AW_window_Motif::WM_max_left_offset, motif->WM_left_offset);
1352
1353#if defined(DEBUG)
1354            fprintf(stderr, "WM_top_offset=%i WM_left_offset=%i (pos from awar: %i/%i, content-pos: %i/%i)\n",
1355                    motif->WM_top_offset, motif->WM_left_offset,
1356                    oposx, oposy, posx, posy);
1357#endif
1358    }
1359}
1360
1361AW_root_Motif::AW_root_Motif()
1362    : last_widget(0),
1363      display(NULL),
1364      context(0),
1365      toplevel_widget(0),
1366      main_widget(0),
1367      main_aww(NULL),
1368      message_shell(0),
1369      foreground(0),
1370      background(0),
1371      fontlist(0),
1372      option_menu_list(NULL),
1373      last_option_menu(NULL),
1374      current_option_menu(NULL),
1375      toggle_field_list(NULL),
1376      last_toggle_field(NULL),
1377      selection_list(NULL),
1378      last_selection_list(NULL),
1379      screen_depth(0),
1380      color_table(NULL),
1381      colormap(0),
1382      help_active(0),
1383      clock_cursor(0),
1384      question_cursor(0),
1385      old_cursor_display(NULL),
1386      old_cursor_window(0),
1387      no_exit(false),
1388      action_hash(NULL)
1389{}
1390
1391AW_root_Motif::~AW_root_Motif() {
1392    GBS_free_hash(action_hash);
1393    XmFontListFree(fontlist);
1394    free(color_table);
1395}
1396
1397void AW_root_Motif::set_cursor(Display *d, Window w, Cursor c) {
1398    XSetWindowAttributes attrs;
1399    old_cursor_display = d;
1400    old_cursor_window = w;
1401
1402    if (c)
1403        attrs.cursor = c;
1404    else
1405        attrs.cursor = None;
1406
1407    if (d && w) {
1408        XChangeWindowAttributes(d, w, CWCursor, &attrs);
1409    }
1410    XChangeWindowAttributes(XtDisplay(main_widget), XtWindow(main_widget),
1411            CWCursor, &attrs);
1412    XFlush(XtDisplay(main_widget));
1413}
1414
1415void AW_root_Motif::normal_cursor() {
1416    set_cursor(old_cursor_display, old_cursor_window, 0);
1417}
1418
1419void AW_server_callback(Widget /*wgt*/, XtPointer aw_cb_struct, XtPointer /*call_data*/) {
1420    AW_cb *cbs = (AW_cb *) aw_cb_struct;
1421
1422    AW_root *root = cbs->aw->get_root();
1423    if (p_global->help_active) {
1424        p_global->help_active = 0;
1425        p_global->normal_cursor();
1426
1427        if (cbs->help_text && ((GBS_string_matches(cbs->help_text, "*.ps", GB_IGNORE_CASE)) ||
1428                               (GBS_string_matches(cbs->help_text, "*.hlp", GB_IGNORE_CASE)) ||
1429                               (GBS_string_matches(cbs->help_text, "*.help", GB_IGNORE_CASE))))
1430        {
1431            AW_help_popup(NULL, cbs->help_text);
1432        }
1433        else {
1434            aw_message("Sorry no help available");
1435        }
1436        return;
1437    }
1438
1439    if (root->is_tracking()) root->track_action(cbs->id);
1440
1441    p_global->set_cursor(XtDisplay(p_global->toplevel_widget),
1442                         XtWindow(p_aww(cbs->aw)->shell),
1443                         p_global->clock_cursor);
1444    cbs->run_callbacks();
1445
1446    XEvent event; // destroy all old events !!!
1447    while (XCheckMaskEvent(XtDisplay(p_global->toplevel_widget),
1448                           ButtonPressMask|ButtonReleaseMask|ButtonMotionMask|
1449                           KeyPressMask|KeyReleaseMask|PointerMotionMask, &event)) {
1450    }
1451
1452    if (p_global->help_active) {
1453        p_global->set_cursor(XtDisplay(p_global->toplevel_widget),
1454                             XtWindow(p_aww(cbs->aw)->shell),
1455                             p_global->question_cursor);
1456    }
1457    else {
1458        p_global->set_cursor(XtDisplay(p_global->toplevel_widget),
1459                             XtWindow(p_aww(cbs->aw)->shell),
1460                             0);
1461    }
1462}
1463
1464// ----------------------------------------------------------------------
1465// force-diff-sync 2964732647236 (remove after merging back to trunk)
1466// ----------------------------------------------------------------------
1467
1468void AW_window::recalc_pos_atShow(AW_PosRecalc pr) {
1469    recalc_pos_at_show = pr;
1470}
1471
1472AW_PosRecalc AW_window::get_recalc_pos_atShow() const {
1473    return recalc_pos_at_show;
1474}
1475
1476void AW_window::recalc_size_atShow(enum AW_SizeRecalc sr) {
1477    if (sr == AW_RESIZE_ANY) {
1478        sr = (recalc_size_at_show == AW_RESIZE_USER) ? AW_RESIZE_USER : AW_RESIZE_DEFAULT;
1479    }
1480    recalc_size_at_show = sr;
1481}
1482
1483
1484
1485// --------------
1486//      focus
1487
1488
1489void AW_window::run_focus_callback() {
1490    if (focus_cb) focus_cb->run_callbacks();
1491}
1492
1493bool AW_window::is_focus_callback(AnyWinCB f) {
1494    return focus_cb && focus_cb->contains(f);
1495}
1496
1497// ---------------
1498//      expose
1499
1500inline void AW_area_management::run_expose_callback() {
1501    if (expose_cb) expose_cb->run_callbacks();
1502}
1503
1504static void AW_exposeCB(Widget /*wgt*/, XtPointer aw_cb_struct, XmDrawingAreaCallbackStruct *call_data) {
1505    XEvent *ev = call_data->event;
1506    AW_area_management *aram = (AW_area_management *) aw_cb_struct;
1507    if (ev->xexpose.count == 0) { // last expose cb
1508        aram->run_expose_callback();
1509    }
1510}
1511
1512void AW_area_management::set_expose_callback(AW_window *aww, const WindowCallback& cb) {
1513    // insert expose callback for draw_area
1514    if (!expose_cb) {
1515        XtAddCallback(area, XmNexposeCallback, (XtCallbackProc) AW_exposeCB,
1516                (XtPointer) this);
1517    }
1518    expose_cb = new AW_cb(aww, cb, 0, expose_cb);
1519}
1520
1521bool AW_area_management::is_expose_callback(AnyWinCB f) {
1522    return expose_cb && expose_cb->contains(f);
1523}
1524
1525bool AW_window::is_expose_callback(AW_area area, AnyWinCB f) {
1526    AW_area_management *aram = MAP_ARAM(area);
1527    return aram && aram->is_expose_callback(f);
1528}
1529
1530void AW_window::force_expose() {
1531    XmDrawingAreaCallbackStruct da_struct;
1532
1533    da_struct.reason = XmCR_EXPOSE;
1534    da_struct.event = (XEvent *) NULL;
1535    da_struct.window = XtWindow(p_w->shell);
1536
1537    XtCallCallbacks(p_w->shell, XmNexposeCallback, (XtPointer) &da_struct);
1538}
1539
1540// ---------------
1541//      resize
1542
1543
1544bool AW_area_management::is_resize_callback(AnyWinCB f) {
1545    return resize_cb && resize_cb->contains(f);
1546}
1547
1548bool AW_window::is_resize_callback(AW_area area, AnyWinCB f) {
1549    AW_area_management *aram = MAP_ARAM(area);
1550    return aram && aram->is_resize_callback(f);
1551}
1552
1553void AW_window::set_window_frame_pos(int x, int y) {
1554    // this will set the position of the frame around the client-area (see also WM_top_offset ..)
1555    XtVaSetValues(p_w->shell, XmNx, (int)x, XmNy, (int)y, NULL);
1556}
1557void AW_window::get_window_content_pos(int& xpos, int& ypos) {
1558    // this will report the position of the client-area (see also WM_top_offset ..)
1559    unsigned short x, y;
1560    XtVaGetValues(p_w->shell, XmNx, &x, XmNy, &y, NULL);
1561    xpos = x;
1562    ypos = y;
1563}
1564
1565void AW_window::get_screen_size(int &width, int &height) {
1566    Screen *screen = XtScreen(p_w->shell);
1567
1568    width  = WidthOfScreen(screen);
1569    height = HeightOfScreen(screen);
1570}
1571
1572bool AW_window::get_mouse_pos(int& x, int& y) {
1573    Display      *= XtDisplay(p_w->shell);
1574    Window        w1 = XtWindow(p_w->shell);
1575    Window        w2;
1576    Window        w3;
1577    int           rx, ry;
1578    int           wx, wy;
1579    unsigned int  mask;
1580
1581    Bool ok = XQueryPointer(d, w1, &w2, &w3, &rx, &ry, &wx, &wy, &mask);
1582
1583    if (ok) {
1584#if defined(DEBUG) && 0
1585        printf("get_mouse_pos: rx/ry=%i/%i wx/wy=%i/%i\n", rx, ry, wx, wy);
1586#endif // DEBUG
1587        x = rx;
1588        y = ry;
1589    }
1590    return ok;
1591}
1592
1593static int is_resize_event(Display *display, XEvent *event, XPointer) {
1594    // Predicate function: checks, if the given event is a ResizeEvent
1595    if (event && (event->type == ResizeRequest || event->type
1596            == ConfigureNotify) && event->xany.display == display) {
1597        return 1;
1598    }
1599    return 0;
1600}
1601
1602static void cleanupResizeEvents(Display *display) {
1603    // Removes redundant resize events from the x-event queue
1604    if (display) {
1605        XLockDisplay(display);
1606        XEvent event;
1607        if (XCheckIfEvent(display, &event, is_resize_event, 0)) {
1608            // Some magic happens here... ;-) (removing redundant events from queue)
1609            while (XCheckIfEvent(display, &event, is_resize_event, 0))
1610                ;
1611            // Keep last Event in queue
1612            XPutBackEvent(display, &event);
1613        }
1614        XUnlockDisplay(display);
1615    }
1616}
1617
1618static void aw_window_avoid_destroy_cb(Widget, AW_window *, XmAnyCallbackStruct *) {
1619    aw_message("If YOU do not know what to answer, how should ARB know?\nPlease think again and answer the prompt!");
1620}
1621static void aw_window_noexit_destroy_cb(Widget,  AW_window *aww, XmAnyCallbackStruct *) {
1622    aww->hide();
1623    // don't exit, when using destroy callback
1624}
1625static void aw_window_destroy_cb(Widget,  AW_window *aww, XmAnyCallbackStruct *) {
1626    AW_root *root = aww->get_root();
1627    if ((p_global->main_aww == aww) || !p_global->main_aww->is_shown()) {
1628#ifdef NDEBUG
1629        if (!aw_ask_sure("quit_by_X", "Are you sure to quit?")) return;
1630#endif
1631        exit(EXIT_SUCCESS);
1632    }
1633    aww->hide();
1634}
1635
1636static void aw_set_delete_window_cb(AW_window *aww, Widget shell, bool allow_close) {
1637    Atom WM_DELETE_WINDOW = XmInternAtom(XtDisplay(shell), (char*)"WM_DELETE_WINDOW", False);
1638
1639    // remove any previous callbacks
1640    XmRemoveWMProtocolCallback(shell, WM_DELETE_WINDOW, (XtCallbackProc)aw_window_avoid_destroy_cb,  (caddr_t)aww);
1641    XmRemoveWMProtocolCallback(shell, WM_DELETE_WINDOW, (XtCallbackProc)aw_window_noexit_destroy_cb, (caddr_t)aww);
1642    XmRemoveWMProtocolCallback(shell, WM_DELETE_WINDOW, (XtCallbackProc)aw_window_destroy_cb,        (caddr_t)aww);
1643
1644    if (!allow_close) {
1645        XmAddWMProtocolCallback(shell, WM_DELETE_WINDOW, (XtCallbackProc)aw_window_avoid_destroy_cb, (caddr_t)aww);
1646    }
1647    else {
1648        AW_root *root = aww->get_root();
1649        if (p_global->no_exit) {
1650            XmAddWMProtocolCallback(shell, WM_DELETE_WINDOW, (XtCallbackProc)aw_window_noexit_destroy_cb, (caddr_t)aww);
1651        }
1652        else {
1653            XmAddWMProtocolCallback(shell, WM_DELETE_WINDOW, (XtCallbackProc)aw_window_destroy_cb, (caddr_t)aww);
1654        }
1655    }
1656}
1657
1658// ----------------------------------------------------------------------
1659// force-diff-sync 8294723642364 (remove after merging back to trunk)
1660// ----------------------------------------------------------------------
1661
1662void AW_window::allow_delete_window(bool allow_close) {
1663    aw_set_delete_window_cb(this, p_w->shell, allow_close);
1664}
1665
1666// ----------------------------------------------------------------------
1667// force-diff-sync 9268347253894 (remove after merging back to trunk)
1668// ----------------------------------------------------------------------
1669
1670bool AW_window::is_shown() const {
1671    // return true if window is shown ( = not invisible and already created)
1672    // Note: does return TRUE!, if window is only minimized by WM
1673    return window_is_shown;
1674}
1675
1676static void aw_update_window_geometry_awars(AW_window *aww) {
1677    AW_window_Motif *motif = p_aww(aww);
1678
1679    short          posx, posy;
1680    unsigned short width, height, borderwidth;
1681    XtVaGetValues(motif->shell, // bad hack
1682                  XmNborderWidth, &borderwidth,
1683                  XmNwidth, &width,
1684                  XmNheight, &height,
1685                  XmNx, &posx,
1686                  XmNy, &posy,
1687                  NULL);
1688
1689    if (motif->knows_WM_offset()) {
1690        posx -= motif->WM_left_offset;
1691        posy -= motif->WM_top_offset;
1692
1693        if (posx<0) posx = 0;
1694        if (posy<0) posy = 0;
1695
1696        aww->store_pos_in_awars(posx, posy);
1697    }
1698#if defined(DEBUG)
1699    else {
1700        fprintf(stderr, "Warning: WM_offsets unknown => did not update awars for window '%s'\n", aww->get_window_title());
1701    }
1702#endif
1703    aww->store_size_in_awars(width, height);
1704}
1705
1706void AW_window::show() {
1707    bool was_shown = true;
1708    if (!window_is_shown) {
1709        all_menus_created();
1710        get_root()->window_show();
1711        window_is_shown = true;
1712        was_shown       = false;
1713    }
1714
1715    int  width, height; // w/o window frame
1716    if (recalc_size_at_show != AW_KEEP_SIZE) {
1717        if (recalc_size_at_show == AW_RESIZE_DEFAULT) {
1718            // window ignores user-size (even if changed inside current session).
1719            // used for question boxes, user masks, ...
1720            window_fit();
1721            get_window_size(width, height);
1722        }
1723        else {
1724            aw_assert(recalc_size_at_show == AW_RESIZE_USER);
1725            // check whether user size is too small and increase to minimum window size
1726
1727            int min_width, min_height;   get_window_size(min_width, min_height);
1728            int user_width, user_height; get_size_from_awars(user_width, user_height);
1729
1730            if (user_width <min_width)  user_width  = min_width;
1731            if (user_height<min_height) user_height = min_height;
1732
1733            set_window_size(user_width, user_height); // restores user size
1734
1735            width  = user_width;
1736            height = user_height;
1737
1738#if defined(DEBUG)
1739            if (!was_shown) { // first popup
1740                // warn about too big default size
1741#define LOWEST_SUPPORTED_SCREEN_X 1280
1742#define LOWEST_SUPPORTED_SCREEN_Y 800
1743
1744                if (min_width>LOWEST_SUPPORTED_SCREEN_X || min_height>LOWEST_SUPPORTED_SCREEN_Y) {
1745                    fprintf(stderr,
1746                            "Warning: Window '%s' won't fit on %ix%i (win=%ix%i)\n",
1747                            get_window_title(),
1748                            LOWEST_SUPPORTED_SCREEN_X, LOWEST_SUPPORTED_SCREEN_Y,
1749                            min_width, min_height);
1750#if defined(DEVEL_RALF)
1751                    aw_assert(0);
1752#endif
1753                }
1754            }
1755#endif
1756        }
1757        store_size_in_awars(width, height);
1758        recalc_size_at_show = AW_KEEP_SIZE;
1759    }
1760    else {
1761        get_window_size(width, height);
1762    }
1763
1764    {
1765        int  posx, posy;
1766        int  swidth, sheight; get_screen_size(swidth, sheight);
1767        bool posIsFrame = false;
1768
1769        switch (recalc_pos_at_show) {
1770            case AW_REPOS_TO_MOUSE_ONCE:
1771                recalc_pos_at_show = AW_KEEP_POS;
1772                // fallthrough
1773            case AW_REPOS_TO_MOUSE: {
1774                int mx, my;
1775                if (!get_mouse_pos(mx, my)) goto FALLBACK_CENTER;
1776
1777                posx   = mx-width/2;
1778                posy   = my-height/2;
1779                break;
1780            }
1781            case AW_REPOS_TO_CENTER:
1782            FALLBACK_CENTER:
1783                posx   = (swidth-width)/2;
1784                posy   = (sheight-height)/4;
1785                break;
1786
1787            case AW_KEEP_POS:
1788                if (was_shown) {
1789                    // user might have moved the window -> store (new) positions
1790                    aw_update_window_geometry_awars(this);
1791                }
1792                get_pos_from_awars(posx, posy);
1793                get_size_from_awars(width, height);
1794                posIsFrame = true;
1795                break;
1796        }
1797
1798        int frameWidth, frameHeight;
1799        if (p_w->knows_WM_offset()) {
1800            frameWidth  = p_w->WM_left_offset;
1801            frameHeight = p_w->WM_top_offset;
1802        }
1803        else {
1804            // estimate
1805            frameWidth  = AW_window_Motif::WM_max_left_offset + 1;
1806            frameHeight = AW_window_Motif::WM_max_top_offset  + 1;
1807        }
1808
1809        if (!posIsFrame) {
1810            posx       -= frameWidth;
1811            posy       -= frameHeight;
1812            posIsFrame  = true;
1813        }
1814
1815        // avoid windows outside of screen (or too near to screen-edges)
1816        {
1817            int maxx = swidth  - 2*frameWidth           - width;
1818            int maxy = sheight - frameWidth-frameHeight - height; // assumes lower border-width == frameWidth
1819
1820            if (posx>maxx) posx = maxx;
1821            if (posy>maxy) posy = maxy;
1822
1823            if (p_w->knows_WM_offset()) {
1824                if (posx<0) posx = 0;
1825                if (posy<0) posy = 0;
1826            }
1827            else {
1828                // workaround a bug leading to wrong WM-offsets (occurs when window-content is placed at screen-border)
1829                // shift window away from border
1830                if (posx<frameWidth)  posx = frameWidth;
1831                if (posy<frameHeight) posy = frameHeight;
1832            }
1833        }
1834
1835        aw_assert(implicated(p_w->knows_WM_offset(), posIsFrame));
1836
1837        // store position and position window
1838        store_pos_in_awars(posx, posy);
1839        set_window_frame_pos(posx, posy);
1840    }
1841
1842    XtPopup(p_w->shell, XtGrabNone);
1843    if (!expose_callback_added) {
1844        set_expose_callback(AW_INFO_AREA, aw_onExpose_calc_WM_offsets); // @@@ should be removed after it was called once
1845        expose_callback_added = true;
1846    }
1847}
1848
1849void AW_window::show_modal() {
1850    recalc_pos_atShow(AW_REPOS_TO_MOUSE);
1851    get_root()->current_modal_window = this;
1852    activate();
1853}
1854
1855void AW_window::hide() {
1856    if (window_is_shown) {
1857        aw_update_window_geometry_awars(this);
1858        if (hide_cb) hide_cb(this);
1859        get_root()->window_hide(this);
1860        window_is_shown = false;
1861    }
1862    XtPopdown(p_w->shell);
1863}
1864
1865void AW_window::hide_or_notify(const char *error) {
1866    if (error) aw_message(error);
1867    else hide();
1868}
1869
1870// ----------------------------------------------------------------------
1871// force-diff-sync 9287423467632 (remove after merging back to trunk)
1872// ----------------------------------------------------------------------
1873
1874void AW_window::on_hide(WindowCallbackSimple call_on_hide) {
1875    hide_cb = call_on_hide;
1876}
1877
1878inline void AW_area_management::run_resize_callback() {
1879    if (resize_cb) resize_cb->run_callbacks();
1880}
1881
1882static void AW_resizeCB_draw_area(Widget /*wgt*/, XtPointer aw_cb_struct, XtPointer /*call_data*/) {
1883    AW_area_management *aram = (AW_area_management *) aw_cb_struct;
1884    cleanupResizeEvents(aram->get_common()->get_display());
1885    aram->run_resize_callback();
1886}
1887
1888void AW_area_management::set_resize_callback(AW_window *aww, const WindowCallback& cb) {
1889    // insert resize callback for draw_area
1890    if (!resize_cb) {
1891        XtAddCallback(area, XmNresizeCallback,
1892                (XtCallbackProc) AW_resizeCB_draw_area, (XtPointer) this);
1893    }
1894    resize_cb = new AW_cb(aww, cb, 0, resize_cb);
1895}
1896
1897// -------------------
1898//      user input
1899
1900
1901static void AW_inputCB_draw_area(Widget wgt, XtPointer aw_cb_struct, XmDrawingAreaCallbackStruct *call_data) {
1902    XEvent             *ev                        = call_data->event;
1903    AW_cb       *cbs                       = (AW_cb *) aw_cb_struct;
1904    AW_window          *aww                       = cbs->aw;
1905    bool                run_callback              = false;
1906    bool                run_double_click_callback = false;
1907    AW_area_management *area                      = 0;
1908    {
1909        int i;
1910        for (i=0; i<AW_MAX_AREA; i++) {
1911            if (p_aww(aww)->areas[i]->get_area() == wgt) {
1912                area = p_aww(aww)->areas[i];
1913                break;
1914            }
1915        }
1916    }
1917
1918    if (ev->xbutton.type == ButtonPress || ev->xbutton.type == ButtonRelease) {
1919        aww->event.button      = AW_MouseButton(ev->xbutton.button);
1920        aww->event.x           = ev->xbutton.x;
1921        aww->event.y           = ev->xbutton.y;
1922        aww->event.keymodifier = (AW_key_mod)(ev->xbutton.state & (AW_KEYMODE_SHIFT|AW_KEYMODE_CONTROL|AW_KEYMODE_ALT));
1923        aww->event.keycode     = AW_KEY_NONE;
1924        aww->event.character   = '\0';
1925
1926        if (ev->xbutton.type == ButtonPress) {
1927            aww->event.type = AW_Mouse_Press;
1928            if (area && area->get_double_click_cb()) {
1929                if ((ev->xbutton.time - area->get_click_time()) < 200) {
1930                    run_double_click_callback = true;
1931                }
1932                else {
1933                    run_callback = true;
1934                }
1935                area->set_click_time(ev->xbutton.time);
1936            }
1937            else {
1938                run_callback = true;
1939            }
1940            aww->event.time = ev->xbutton.time;
1941        }
1942        else if (ev->xbutton.type == ButtonRelease) {
1943            aww->event.type = AW_Mouse_Release;
1944            run_callback = true;
1945            // keep event.time set in ButtonPress-branch
1946        }
1947    }
1948    else if (ev->xkey.type == KeyPress || ev->xkey.type == KeyRelease) {
1949        aww->event.time = ev->xbutton.time;
1950
1951        const awXKeymap *mykey = aw_xkey_2_awkey(&(ev->xkey));
1952
1953        aww->event.keycode = mykey->awkey;
1954        aww->event.keymodifier = mykey->awmod;
1955
1956        if (mykey->awstr) {
1957            aww->event.character = mykey->awstr[0];
1958        }
1959        else {
1960            aww->event.character = 0;
1961        }
1962
1963        if (ev->xkey.type == KeyPress) {
1964            aww->event.type = AW_Keyboard_Press;
1965        }
1966        else {
1967            aww->event.type = AW_Keyboard_Release;
1968        }
1969        aww->event.button = AW_BUTTON_NONE;
1970        aww->event.x = ev->xbutton.x;
1971        aww->event.y = ev->xbutton.y;
1972
1973        if (!mykey->awmod && mykey->awkey >= AW_KEY_F1 && mykey->awkey
1974                <= AW_KEY_F12 && p_aww(aww)->modes_f_callbacks && p_aww(aww)->modes_f_callbacks[mykey->awkey-AW_KEY_F1]
1975                && aww->event.type == AW_Keyboard_Press) {
1976            p_aww(aww)->modes_f_callbacks[mykey->awkey-AW_KEY_F1]->run_callbacks();
1977        }
1978        else {
1979            run_callback = true;
1980        }
1981    }
1982
1983    if (run_double_click_callback) {
1984        if (cbs->help_text == (char*)1) {
1985            cbs->run_callbacks();
1986        }
1987        else {
1988            if (area)
1989                area->get_double_click_cb()->run_callbacks();
1990        }
1991    }
1992
1993    if (run_callback && (cbs->help_text == (char*)0)) {
1994        cbs->run_callbacks();
1995    }
1996}
1997
1998void AW_area_management::set_input_callback(AW_window *aww, const WindowCallback& wcb) {
1999    XtAddCallback(area, XmNinputCallback,
2000            (XtCallbackProc)AW_inputCB_draw_area,
2001            (XtPointer)new AW_cb(aww, wcb));
2002}
2003
2004void AW_area_management::set_double_click_callback(AW_window *aww, const WindowCallback& wcb) {
2005    double_click_cb = new AW_cb(aww, wcb, (char*)0, double_click_cb);
2006}
2007
2008void AW_window::set_double_click_callback(AW_area area, const WindowCallback& wcb) {
2009    AW_area_management *aram = MAP_ARAM(area);
2010    if (!aram)
2011        return;
2012    aram->set_double_click_callback(this, wcb);
2013}
2014
2015// ---------------
2016//      motion
2017
2018static void AW_motionCB(Widget /*w*/, XtPointer aw_cb_struct, XEvent *ev, Boolean*) {
2019    AW_cb *cbs = (AW_cb *) aw_cb_struct;
2020
2021    cbs->aw->event.type    = AW_Mouse_Drag;
2022    cbs->aw->event.x       = ev->xmotion.x;
2023    cbs->aw->event.y       = ev->xmotion.y;
2024    cbs->aw->event.keycode = AW_KEY_NONE;
2025
2026    cbs->run_callbacks();
2027}
2028void AW_area_management::set_motion_callback(AW_window *aww, const WindowCallback& wcb) {
2029    XtAddEventHandler(area, ButtonMotionMask, False,
2030                      AW_motionCB, (XtPointer) new AW_cb(aww, wcb, ""));
2031}
2032static long destroy_awar(const char *, long val, void *) {
2033    AW_awar *awar = (AW_awar*)val;
2034    delete   awar;
2035    return 0; // remove from hash
2036}
2037
2038void AW_root::exit_variables() {
2039    if (hash_table_for_variables) {
2040        GBS_hash_do_loop(hash_table_for_variables, destroy_awar, NULL);
2041        GBS_free_hash(hash_table_for_variables);
2042        hash_table_for_variables = NULL;
2043    }
2044
2045    if (hash_for_windows) {
2046        GBS_free_hash(hash_for_windows);
2047        hash_for_windows = NULL;
2048    }
2049
2050    if (application_database) {
2051        GBDATA *prop_main    = application_database;
2052        application_database = NULL;
2053        GB_close(prop_main);
2054    }
2055}
2056
2057void AW_root::exit_root() {
2058    aw_uninstall_xkeys();
2059}
2060
2061void AW_window::update_scrollbar_settings_from_awars(AW_orientation orientation) {
2062    AW_screen_area scrolled;
2063    get_scrollarea_size(&scrolled);
2064
2065    if (orientation == AW_HORIZONTAL) {
2066        XtVaSetValues(p_w->scroll_bar_horizontal, XmNpageIncrement, (int)(scrolled.r*(window_local_awar("horizontal_page_increment")->read_int()*0.01)), NULL);
2067        XtVaSetValues(p_w->scroll_bar_horizontal, XmNincrement,     (int)(window_local_awar("scroll_width_horizontal")->read_int()), NULL);
2068        XtVaSetValues(p_w->scroll_bar_horizontal, XmNrepeatDelay,   (int)(window_local_awar("scroll_delay_horizontal")->read_int()), NULL);
2069    }
2070    else {
2071        XtVaSetValues(p_w->scroll_bar_vertical, XmNpageIncrement, (int)(scrolled.b*(window_local_awar("vertical_page_increment")->read_int()*0.01)), NULL);
2072        XtVaSetValues(p_w->scroll_bar_vertical, XmNincrement,     (int)(window_local_awar("scroll_width_vertical")->read_int()), NULL);
2073        XtVaSetValues(p_w->scroll_bar_vertical, XmNrepeatDelay,   (int)(window_local_awar("scroll_delay_vertical")->read_int()), NULL);
2074    }
2075}
2076
2077void AW_area_management::create_devices(AW_window *aww, AW_area ar) {
2078    AW_root *root = aww->get_root();
2079    common = new AW_common_Xm(XtDisplay(area), XtWindow(area), p_global->color_table, aww->color_table, aww->color_table_size, aww, ar);
2080}
2081
2082AW_color_idx AW_window::alloc_named_data_color(int colnum, const char *colorname) {
2083    if (!color_table_size) {
2084        color_table_size = AW_STD_COLOR_IDX_MAX + colnum;
2085        color_table      = (AW_rgb*)malloc(sizeof(AW_rgb) *color_table_size);
2086        for (int i = 0; i<color_table_size; ++i) color_table[i] = AW_NO_COLOR;
2087    }
2088    else {
2089        if (colnum>=color_table_size) {
2090            long new_size  = colnum+8;
2091            realloc_unleaked(color_table, new_size*sizeof(AW_rgb)); // valgrinders : never freed because AW_window never is freed
2092            if (!color_table) GBK_terminate("out of memory");
2093            for (int i = color_table_size; i<new_size; ++i) color_table[i] = AW_NO_COLOR;
2094            color_table_size                                               = new_size;
2095        }
2096    }
2097    XColor xcolor_returned, xcolor_exakt;
2098
2099    if (p_global->screen_depth == 1) { // Black and White Monitor
2100        static int col = 1;
2101        if (colnum == AW_DATA_BG) {
2102            col = 1;
2103            if (strcmp(colorname, "white"))
2104                col *= -1;
2105        }
2106        if (col==1) {
2107            color_table[colnum] = WhitePixelOfScreen(XtScreen(p_global->toplevel_widget));
2108        }
2109        else {
2110            color_table[colnum] = BlackPixelOfScreen(XtScreen(p_global->toplevel_widget));
2111        }
2112        if (colnum == AW_DATA_BG)
2113            col *= -1;
2114    }
2115    else { // Color monitor
2116        if (color_table[colnum] != AW_NO_COLOR) {
2117            unsigned long color = color_table[colnum];
2118            XFreeColors(p_global->display, p_global->colormap, &color, 1, 0);
2119        }
2120        if (XAllocNamedColor(p_global->display, p_global->colormap, colorname, &xcolor_returned, &xcolor_exakt) == 0) {
2121            aw_message(GBS_global_string("XAllocColor failed: %s\n", colorname));
2122            color_table[colnum] = AW_NO_COLOR;
2123        }
2124        else {
2125            color_table[colnum] = xcolor_returned.pixel;
2126        }
2127    }
2128    if (colnum == AW_DATA_BG) {
2129        XtVaSetValues(p_w->areas[AW_MIDDLE_AREA]->get_area(), XmNbackground, color_table[colnum], NULL);
2130    }
2131    return (AW_color_idx)colnum;
2132}
2133
2134void AW_window::create_devices() {
2135    unsigned long background_color;
2136    if (p_w->areas[AW_INFO_AREA]) {
2137        p_w->areas[AW_INFO_AREA]->create_devices(this, AW_INFO_AREA);
2138        XtVaGetValues(p_w->areas[AW_INFO_AREA]->get_area(), XmNbackground, &background_color, NULL);
2139        p_global->color_table[AW_WINDOW_DRAG] = background_color ^ p_global->color_table[AW_WINDOW_FG];
2140    }
2141    if (p_w->areas[AW_MIDDLE_AREA]) {
2142        p_w->areas[AW_MIDDLE_AREA]->create_devices(this, AW_MIDDLE_AREA);
2143    }
2144    if (p_w->areas[AW_BOTTOM_AREA]) {
2145        p_w->areas[AW_BOTTOM_AREA]->create_devices(this, AW_BOTTOM_AREA);
2146    }
2147}
2148
2149void aw_insert_default_help_entries(AW_window *aww) {
2150    aww->insert_help_topic("Click here and then on the questionable button/menu/...", "q", 0, AWM_ALL, AW_help_entry_pressed);
2151
2152    aww->insert_help_topic("How to use help", "H", "help.hlp", AWM_ALL, makeHelpCallback("help.hlp"));
2153    aww->insert_help_topic("ARB help",        "A", "arb.hlp",  AWM_ALL, makeHelpCallback("arb.hlp"));
2154}
2155
2156inline char *strdup_getlen(const char *str, int& len) {
2157    len = strlen(str);
2158    return GB_strduplen(str, len);
2159}
2160Label::Label(const char *labeltext, AW_window *aww) {
2161    imageref = AW_IS_IMAGEREF(labeltext);
2162    if (imageref) {
2163        label = strdup_getlen(AW_get_pixmapPath(labeltext+1), len);
2164    }
2165    else {
2166        AW_awar *is_awar = aww->get_root()->label_is_awar(labeltext);
2167
2168        if (is_awar) { // for labels displaying awar values, insert dummy text here
2169            len = aww->get_at().length_of_buttons - 2;
2170            if (len < 1) len = 1;
2171
2172            label = (char*)malloc(len+1);
2173            memset(label, 'y', len);
2174            label[len] = 0;
2175        }
2176        else {
2177            label = strdup_getlen(labeltext, len);
2178        }
2179    }
2180}
2181
2182void AW_label_in_awar_list(AW_window *aww, Widget widget, const char *str) {
2183    AW_awar *is_awar = aww->get_root()->label_is_awar(str);
2184    if (is_awar) {
2185        char *display = is_awar->read_as_string();
2186
2187        if (!display) {
2188            aw_assert(0); // awar not found
2189            freeset(display, GBS_global_string_copy("<undef AWAR: %s>", str));
2190        }
2191        if (!display[0]) freeset(display, strdup(" ")); // empty string causes wrong-sized buttons
2192
2193        aww->update_label(widget, display);
2194        free(display);
2195
2196        is_awar->tie_widget(0, widget, AW_WIDGET_LABEL_FIELD, aww);
2197    }
2198}
2199
2200static long aw_loop_get_window_geometry(const char *, long val, void *) {
2201    aw_update_window_geometry_awars((AW_window *)val);
2202    return val;
2203}
2204void aw_update_all_window_geometry_awars(AW_root *awr) {
2205    GBS_hash_do_loop(awr->hash_for_windows, aw_loop_get_window_geometry, NULL);
2206}
2207
2208static long aw_loop_forget_window_geometry(const char *, long val, void *) {
2209    ((AW_window*)val)->reset_geometry_awars();
2210    return val;
2211}
2212void AW_forget_all_window_geometry(AW_window *aww) {
2213    AW_root *awr = aww->get_root();
2214    GBS_hash_do_loop(awr->hash_for_windows, aw_loop_forget_window_geometry, NULL); // reset geometry for used windows
2215
2216    // reset geometry in stored, unused windows
2217    GBDATA         *gb_props = awr->check_properties(NULL);
2218    GB_transaction  ta(gb_props);
2219    GBDATA         *gb_win   = GB_search(gb_props, LAYOUT_AWAR_ROOT, GB_FIND);
2220    if (gb_win) {
2221        for (GBDATA *gbw = GB_child(gb_win); gbw; ) {
2222            const char *key     = GB_read_key_pntr(gbw);
2223            long        usedWin = GBS_read_hash(awr->hash_for_windows, key);
2224            GBDATA     *gbnext  = GB_nextChild(gbw);
2225
2226            if (!usedWin) {
2227                GB_ERROR error = GB_delete(gbw);
2228                aw_message_if(error);
2229            }
2230            gbw = gbnext;
2231        }
2232    }
2233}
2234
2235static const char *existingPixmap(const char *icon_relpath, const char *name) {
2236    const char *icon_relname  = GBS_global_string("%s/%s.xpm", icon_relpath, name);
2237    const char *icon_fullname = AW_get_pixmapPath(icon_relname);
2238
2239    if (!GB_is_regularfile(icon_fullname)) icon_fullname = NULL;
2240
2241    return icon_fullname;
2242}
2243
2244
2245static Pixmap getIcon(Screen *screen, const char *iconName, Pixel foreground, Pixel background) {
2246    static SmartCustomPtr(GB_HASH, GBS_free_hash) icon_hash;
2247    if (icon_hash.isNull()) {
2248        icon_hash = GBS_create_hash(100, GB_MIND_CASE);
2249    }
2250
2251    Pixmap pixmap = GBS_read_hash(&*icon_hash, iconName);
2252
2253    if (!pixmap && iconName) {
2254        const char *iconFile = existingPixmap("icons", iconName);
2255
2256        if (iconFile) {
2257            char *ico = strdup(iconFile);
2258            pixmap    = XmGetPixmap(screen, ico, foreground, background);
2259            GBS_write_hash(&*icon_hash, iconName, pixmap);
2260            free(ico);
2261        }
2262    }
2263
2264    return pixmap;
2265}
2266
2267Widget aw_create_shell(AW_window *aww, bool allow_resize, bool allow_close, int width, int height, int posx, int posy) { // @@@ move into AW_window
2268    AW_root *root = aww->get_root();
2269    Widget shell;
2270
2271    // set minimum window size to size provided by init
2272    if (width >aww->get_at().max_x_size) aww->get_at().max_x_size = width;
2273    if (height>aww->get_at().max_y_size) aww->get_at().max_y_size = height;
2274
2275    bool has_user_geometry = false;
2276    if (!GBS_read_hash(root->hash_for_windows, aww->get_window_id())) {
2277        GBS_write_hash(root->hash_for_windows, aww->get_window_id(), (long)aww);
2278
2279        aww->create_user_geometry_awars(posx, posy, width, height);
2280    }
2281    {
2282        int user_width, user_height; aww->get_size_from_awars(user_width, user_height);
2283        int user_posx,  user_posy;   aww->get_pos_from_awars(user_posx,  user_posy);
2284
2285        if (allow_resize) {
2286            if (width != user_width) { width = user_width; has_user_geometry = true; }
2287            if (height != user_height) { height = user_height; has_user_geometry = true; }
2288        }
2289
2290        // @@@ FIXME:  maximum should be set to current screen size minus some offset
2291        // to ensure that windows do not appear outside screen
2292        if (posx != user_posx) { posx = user_posx; has_user_geometry = true; }
2293        if (posy != user_posy) { posy = user_posy; has_user_geometry = true; }
2294
2295        if (has_user_geometry) {
2296            aww->recalc_size_atShow(AW_RESIZE_USER); // keep user geometry (only if user size is smaller than default size, the latter is used)
2297        }
2298        else { // no geometry yet
2299            aww->recalc_pos_atShow(AW_REPOS_TO_MOUSE_ONCE); // popup the window at current mouse position
2300        }
2301    }
2302   
2303    if (allow_resize) {
2304        // create the window big enough to ensure that all widgets
2305        // are created in visible area (otherwise widget are crippled).
2306        // window will be resized later (on show)
2307
2308        width  = WIDER_THAN_SCREEN;
2309        height = HIGHER_THAN_SCREEN;
2310
2311        aww->recalc_size_atShow(AW_RESIZE_ANY);
2312    }
2313
2314    Widget  father      = p_global->toplevel_widget;
2315    Screen *screen      = XtScreen(father);
2316    Pixmap  icon_pixmap = getIcon(screen, aww->window_defaults_name, p_global->foreground, p_global->background);
2317
2318    if (!icon_pixmap) {
2319        icon_pixmap = getIcon(screen, root->program_name, p_global->foreground, p_global->background);
2320    }
2321
2322    if (!icon_pixmap) {
2323        GBK_terminatef("Missing icon pixmap for window '%s'\n", aww->window_defaults_name);
2324    }
2325    else if (icon_pixmap == XmUNSPECIFIED_PIXMAP) {
2326        GBK_terminatef("Failed to load icon pixmap for window '%s'\n", aww->window_defaults_name);
2327    }
2328
2329    int focusPolicy = root->focus_follows_mouse ? XmPOINTER : XmEXPLICIT;
2330
2331    {
2332        aw_xargs args(9);
2333
2334        args.add(XmNwidth, width);
2335        args.add(XmNheight, height);
2336        args.add(XmNx, posx);
2337        args.add(XmNy, posy);
2338        args.add(XmNtitle, (XtArgVal)aww->window_name);
2339        args.add(XmNiconName, (XtArgVal)aww->window_name);
2340        args.add(XmNkeyboardFocusPolicy, focusPolicy);
2341        args.add(XmNdeleteResponse, XmDO_NOTHING);
2342        args.add(XtNiconPixmap, icon_pixmap);
2343
2344        if (!p_global->main_widget || !p_global->main_aww->is_shown()) {
2345            shell = XtCreatePopupShell("editor", applicationShellWidgetClass, father, args.list(), args.size());
2346        }
2347        else {
2348            shell = XtCreatePopupShell("transient", transientShellWidgetClass, father, args.list(), args.size());
2349        }
2350    }
2351
2352    if (!p_global->main_widget) {
2353        p_global->main_widget = shell;
2354        p_global->main_aww    = aww;
2355    }
2356    else {
2357        if (!p_global->main_aww->is_shown()) {  // now i am the root window
2358            p_global->main_widget = shell;
2359            p_global->main_aww    = aww;
2360        }
2361    }
2362
2363    aw_set_delete_window_cb(aww, shell, allow_close);
2364
2365    // set icon window (for window managers where iconified applications are dropped onto desktop or similar)
2366    {
2367        Window icon_window;
2368        XtVaGetValues(shell, XmNiconWindow, &icon_window, NULL);
2369
2370        Display *dpy = XtDisplay(shell);
2371        if (!icon_window) {
2372            XSetWindowAttributes attr;
2373            attr.background_pixmap = icon_pixmap;
2374
2375            int          xpos, ypos;
2376            unsigned int xsize, ysize, borderwidth, depth;
2377            Window       wroot;
2378
2379            if (XGetGeometry(dpy, icon_pixmap, &wroot, &xpos, &ypos, &xsize, &ysize, &borderwidth, &depth)) {
2380                icon_window = XCreateWindow(dpy, wroot, 0, 0, xsize, ysize, 0, depth, CopyFromParent, CopyFromParent, CWBackPixmap, &attr);
2381            }
2382        }
2383        if (!icon_window) {
2384            XtVaSetValues(shell, XmNiconPixmap, icon_pixmap, NULL);
2385        }
2386        else {
2387            XtVaSetValues(shell, XmNiconWindow, icon_window, NULL);
2388            XSetWindowBackgroundPixmap(dpy, icon_window, icon_pixmap);
2389            XClearWindow(dpy, icon_window);
2390        }
2391    }
2392
2393    return shell;
2394}
2395
2396
2397void aw_realize_widget(AW_window *aww) {
2398    if (p_aww(aww)->areas[AW_INFO_AREA] && p_aww(aww)->areas[AW_INFO_AREA]->get_form()) {
2399        XtManageChild(p_aww(aww)->areas[AW_INFO_AREA]->get_form());
2400    }
2401    if (p_aww(aww)->areas[AW_MIDDLE_AREA] && p_aww(aww)->areas[AW_MIDDLE_AREA]->get_form()) {
2402        XtManageChild(p_aww(aww)->areas[AW_MIDDLE_AREA]->get_form());
2403    }
2404    if (p_aww(aww)->areas[AW_BOTTOM_AREA] && p_aww(aww)->areas[AW_BOTTOM_AREA]->get_form()) {
2405        XtManageChild(p_aww(aww)->areas[AW_BOTTOM_AREA]->get_form());
2406    }
2407    XtRealizeWidget(p_aww(aww)->shell);
2408    p_aww(aww)->WM_top_offset = AW_CALC_OFFSET_ON_EXPOSE;
2409}
2410
2411void AW_window_menu_modes::init(AW_root *root_in, const char *wid, const char *windowname, int  width, int height) { 
2412    Widget      main_window;
2413    Widget      help_popup;
2414    Widget      help_label;
2415    Widget      separator;
2416    Widget      form1;
2417    Widget      form2;
2418    const char *help_button   = "HELP";
2419    const char *help_mnemonic = "H";
2420
2421#if defined(DUMP_MENU_LIST)
2422    initMenuListing(windowname);
2423#endif // DUMP_MENU_LIST
2424    root = root_in; // for macro
2425    window_name = strdup(windowname);
2426    window_defaults_name = GBS_string_2_key(wid);
2427
2428    int posx = 50;
2429    int posy = 50;
2430
2431    p_w->shell = aw_create_shell(this, true, true, width, height, posx, posy);
2432
2433    main_window = XtVaCreateManagedWidget("mainWindow1",
2434                                          xmMainWindowWidgetClass, p_w->shell,
2435                                          NULL);
2436
2437    p_w->menu_bar[0] = XtVaCreateManagedWidget("menu1", xmRowColumnWidgetClass,
2438                                               main_window,
2439                                               XmNrowColumnType, XmMENU_BAR,
2440                                               NULL);
2441
2442    // create shell for help-cascade
2443    help_popup = XtVaCreatePopupShell("menu_shell", xmMenuShellWidgetClass,
2444                                      p_w->menu_bar[0],
2445                                      XmNwidth, 1,
2446                                      XmNheight, 1,
2447                                      XmNallowShellResize, true,
2448                                      XmNoverrideRedirect, true,
2449                                      NULL);
2450
2451    // create row column in Pull-Down shell
2452    p_w->help_pull_down = XtVaCreateWidget("menu_row_column",
2453                                           xmRowColumnWidgetClass, help_popup,
2454                                           XmNrowColumnType, XmMENU_PULLDOWN,
2455                                           NULL);
2456
2457    // create HELP-label in menu bar
2458    help_label = XtVaCreateManagedWidget("menu1_top_b1",
2459                                         xmCascadeButtonWidgetClass, p_w->menu_bar[0],
2460                                         RES_CONVERT(XmNlabelString, help_button),
2461                                         RES_CONVERT(XmNmnemonic, help_mnemonic),
2462                                         XmNsubMenuId, p_w->help_pull_down, NULL);
2463    XtVaSetValues(p_w->menu_bar[0], XmNmenuHelpWidget, help_label, NULL);
2464    root->make_sensitive(help_label, AWM_ALL);
2465
2466    form1 = XtVaCreateManagedWidget("form1",
2467                                    xmFormWidgetClass,
2468                                    main_window,
2469                                    // XmNwidth, width,
2470                                    // XmNheight, height,
2471                                    XmNresizePolicy, XmRESIZE_NONE,
2472                                    // XmNx, 0,
2473                                    // XmNy, 0,
2474                                    NULL);
2475
2476    p_w->mode_area = XtVaCreateManagedWidget("mode area",
2477                                             xmDrawingAreaWidgetClass,
2478                                             form1,
2479                                             XmNresizePolicy, XmRESIZE_NONE,
2480                                             XmNwidth, 38,
2481                                             XmNheight, height,
2482                                             XmNx, 0,
2483                                             XmNy, 0,
2484                                             XmNleftOffset, 0,
2485                                             XmNtopOffset, 0,
2486                                             XmNbottomAttachment, XmATTACH_FORM,
2487                                             XmNleftAttachment, XmATTACH_POSITION,
2488                                             XmNtopAttachment, XmATTACH_POSITION,
2489                                             XmNmarginHeight, 2,
2490                                             XmNmarginWidth, 1,
2491                                             NULL);
2492
2493    separator = XtVaCreateManagedWidget("separator",
2494                                        xmSeparatorWidgetClass,
2495                                        form1,
2496                                        XmNx, 37,
2497                                        XmNshadowThickness, 4,
2498                                        XmNorientation, XmVERTICAL,
2499                                        XmNbottomAttachment, XmATTACH_FORM,
2500                                        XmNtopAttachment, XmATTACH_FORM,
2501                                        XmNleftAttachment, XmATTACH_NONE,
2502                                        XmNleftWidget, NULL,
2503                                        XmNrightAttachment, XmATTACH_NONE,
2504                                        XmNleftOffset, 70,
2505                                        XmNleftPosition, 0,
2506                                        NULL);
2507
2508    form2 = XtVaCreateManagedWidget("form2",
2509                                    xmFormWidgetClass,
2510                                    form1,
2511                                    XmNwidth, width,
2512                                    XmNheight, height,
2513                                    XmNtopOffset, 0,
2514                                    XmNbottomOffset, 0,
2515                                    XmNleftOffset, 0,
2516                                    XmNrightOffset, 0,
2517                                    XmNrightAttachment, XmATTACH_FORM,
2518                                    XmNbottomAttachment, XmATTACH_FORM,
2519                                    XmNleftAttachment, XmATTACH_WIDGET,
2520                                    XmNleftWidget, separator,
2521                                    XmNtopAttachment, XmATTACH_POSITION,
2522                                    XmNresizePolicy, XmRESIZE_NONE,
2523                                    XmNx, 0,
2524                                    XmNy, 0,
2525                                    NULL);
2526    p_w->areas[AW_INFO_AREA] =
2527        new AW_area_management(form2, XtVaCreateManagedWidget("info_area",
2528                                                              xmDrawingAreaWidgetClass,
2529                                                              form2,
2530                                                              XmNheight, 0,
2531                                                              XmNbottomAttachment, XmATTACH_NONE,
2532                                                              XmNtopAttachment, XmATTACH_FORM,
2533                                                              XmNleftAttachment, XmATTACH_FORM,
2534                                                              XmNrightAttachment, XmATTACH_FORM,
2535                                                              XmNmarginHeight, 2,
2536                                                              XmNmarginWidth, 2,
2537                                                              NULL));
2538
2539    p_w->areas[AW_BOTTOM_AREA] =
2540        new AW_area_management(form2, XtVaCreateManagedWidget("bottom_area",
2541                                                              xmDrawingAreaWidgetClass,
2542                                                              form2,
2543                                                              XmNheight, 0,
2544                                                              XmNbottomAttachment, XmATTACH_FORM,
2545                                                              XmNtopAttachment, XmATTACH_NONE,
2546                                                              XmNleftAttachment, XmATTACH_FORM,
2547                                                              XmNrightAttachment, XmATTACH_FORM,
2548                                                              NULL));
2549
2550    p_w->scroll_bar_horizontal = XtVaCreateManagedWidget("scroll_bar_horizontal",
2551                                                         xmScrollBarWidgetClass,
2552                                                         form2,
2553                                                         XmNheight, 15,
2554                                                         XmNminimum, 0,
2555                                                         XmNmaximum, AW_SCROLL_MAX,
2556                                                         XmNincrement, 10,
2557                                                         XmNsliderSize, AW_SCROLL_MAX,
2558                                                         XmNrightAttachment, XmATTACH_FORM,
2559                                                         XmNbottomAttachment, XmATTACH_FORM,
2560                                                         XmNbottomOffset, 0,
2561                                                         XmNleftAttachment, XmATTACH_FORM,
2562                                                         XmNtopAttachment, XmATTACH_NONE,
2563                                                         XmNorientation, XmHORIZONTAL,
2564                                                         XmNrightOffset, 18,
2565                                                         NULL);
2566
2567    p_w->scroll_bar_vertical = XtVaCreateManagedWidget("scroll_bar_vertical",
2568                                                       xmScrollBarWidgetClass,
2569                                                       form2,
2570                                                       XmNwidth, 15,
2571                                                       XmNminimum, 0,
2572                                                       XmNmaximum, AW_SCROLL_MAX,
2573                                                       XmNincrement, 10,
2574                                                       XmNsliderSize, AW_SCROLL_MAX,
2575                                                       XmNrightAttachment, XmATTACH_FORM,
2576                                                       XmNbottomAttachment, XmATTACH_WIDGET,
2577                                                       XmNbottomWidget, p_w->scroll_bar_horizontal,
2578                                                       XmNbottomOffset, 3,
2579                                                       XmNleftOffset, 3,
2580                                                       XmNrightOffset, 3,
2581                                                       XmNleftAttachment, XmATTACH_NONE,
2582                                                       XmNtopAttachment, XmATTACH_WIDGET,
2583                                                       XmNtopWidget, INFO_WIDGET,
2584                                                       NULL);
2585
2586    p_w->frame = XtVaCreateManagedWidget("draw_area",
2587                                         xmFrameWidgetClass,
2588                                         form2,
2589                                         XmNshadowType, XmSHADOW_IN,
2590                                         XmNshadowThickness, 2,
2591                                         XmNleftOffset, 3,
2592                                         XmNtopOffset, 3,
2593                                         XmNbottomOffset, 3,
2594                                         XmNrightOffset, 3,
2595                                         XmNbottomAttachment, XmATTACH_WIDGET,
2596                                         XmNbottomWidget, p_w->scroll_bar_horizontal,
2597                                         XmNtopAttachment, XmATTACH_FORM,
2598                                         XmNtopOffset, 0,
2599                                         XmNleftAttachment, XmATTACH_FORM,
2600                                         XmNrightAttachment, XmATTACH_WIDGET,
2601                                         XmNrightWidget, p_w->scroll_bar_vertical,
2602                                         NULL);
2603
2604    p_w->areas[AW_MIDDLE_AREA] =
2605        new AW_area_management(p_w->frame, XtVaCreateManagedWidget("draw area",
2606                                                                   xmDrawingAreaWidgetClass,
2607                                                                   p_w->frame,
2608                                                                   XmNmarginHeight, 0,
2609                                                                   XmNmarginWidth, 0,
2610                                                                   NULL));
2611
2612    XmMainWindowSetAreas(main_window, p_w->menu_bar[0], (Widget) NULL, (Widget) NULL, (Widget) NULL, form1);
2613
2614    aw_realize_widget(this);
2615
2616    create_devices();
2617    aw_insert_default_help_entries(this);
2618    create_window_variables();
2619}
2620
2621void AW_window_menu::init(AW_root *root_in, const char *wid, const char *windowname, int width, int height) { 
2622    Widget      main_window;
2623    Widget      help_popup;
2624    Widget      help_label;
2625    Widget      separator;
2626    Widget      form1;
2627    Widget      form2;
2628    const char *help_button   = "HELP";
2629    const char *help_mnemonic = "H";
2630
2631#if defined(DUMP_MENU_LIST)
2632    initMenuListing(windowname);
2633#endif // DUMP_MENU_LIST
2634    root = root_in; // for macro
2635    window_name = strdup(windowname);
2636    window_defaults_name = GBS_string_2_key(wid);
2637
2638    int posx = 50;
2639    int posy = 50;
2640
2641    p_w->shell = aw_create_shell(this, true, true, width, height, posx, posy);
2642
2643    main_window = XtVaCreateManagedWidget("mainWindow1",
2644                                          xmMainWindowWidgetClass, p_w->shell,
2645                                          NULL);
2646
2647    p_w->menu_bar[0] = XtVaCreateManagedWidget("menu1", xmRowColumnWidgetClass,
2648                                               main_window,
2649                                               XmNrowColumnType, XmMENU_BAR,
2650                                               NULL);
2651
2652    // create shell for help-cascade
2653    help_popup = XtVaCreatePopupShell("menu_shell", xmMenuShellWidgetClass,
2654                                      p_w->menu_bar[0],
2655                                      XmNwidth, 1,
2656                                      XmNheight, 1,
2657                                      XmNallowShellResize, true,
2658                                      XmNoverrideRedirect, true,
2659                                      NULL);
2660
2661    // create row column in Pull-Down shell
2662    p_w->help_pull_down = XtVaCreateWidget("menu_row_column",
2663                                           xmRowColumnWidgetClass, help_popup,
2664                                           XmNrowColumnType, XmMENU_PULLDOWN,
2665                                           NULL);
2666
2667    // create HELP-label in menu bar
2668    help_label = XtVaCreateManagedWidget("menu1_top_b1",
2669                                         xmCascadeButtonWidgetClass, p_w->menu_bar[0],
2670                                         RES_CONVERT(XmNlabelString, help_button),
2671                                         RES_CONVERT(XmNmnemonic, help_mnemonic),
2672                                         XmNsubMenuId, p_w->help_pull_down, NULL);
2673    XtVaSetValues(p_w->menu_bar[0], XmNmenuHelpWidget, help_label, NULL);
2674    root->make_sensitive(help_label, AWM_ALL);
2675
2676    form1 = XtVaCreateManagedWidget("form1",
2677                                    xmFormWidgetClass,
2678                                    main_window,
2679                                    // XmNwidth, width,
2680                                    // XmNheight, height,
2681                                    XmNresizePolicy, XmRESIZE_NONE,
2682                                    // XmNx, 0,
2683                                    // XmNy, 0,
2684                                    NULL);
2685
2686    p_w->mode_area = XtVaCreateManagedWidget("mode area",
2687                                             xmDrawingAreaWidgetClass,
2688                                             form1,
2689                                             XmNresizePolicy, XmRESIZE_NONE,
2690                                             XmNwidth, 17,
2691                                             XmNheight, height,
2692                                             XmNx, 0,
2693                                             XmNy, 0,
2694                                             XmNleftOffset, 0,
2695                                             XmNtopOffset, 0,
2696                                             XmNbottomAttachment, XmATTACH_FORM,
2697                                             XmNleftAttachment, XmATTACH_POSITION,
2698                                             XmNtopAttachment, XmATTACH_POSITION,
2699                                             XmNmarginHeight, 2,
2700                                             XmNmarginWidth, 1,
2701                                             NULL);
2702
2703    separator = p_w->mode_area;
2704
2705    form2 = XtVaCreateManagedWidget("form2",
2706                                    xmFormWidgetClass,
2707                                    form1,
2708                                    XmNwidth, width,
2709                                    XmNheight, height,
2710                                    XmNtopOffset, 0,
2711                                    XmNbottomOffset, 0,
2712                                    XmNleftOffset, 0,
2713                                    XmNrightOffset, 0,
2714                                    XmNrightAttachment, XmATTACH_FORM,
2715                                    XmNbottomAttachment, XmATTACH_FORM,
2716                                    XmNleftAttachment, XmATTACH_WIDGET,
2717                                    XmNleftWidget, separator,
2718                                    XmNtopAttachment, XmATTACH_POSITION,
2719                                    XmNresizePolicy, XmRESIZE_NONE,
2720                                    XmNx, 0,
2721                                    XmNy, 0,
2722                                    NULL);
2723    p_w->areas[AW_INFO_AREA] =
2724        new AW_area_management(form2, XtVaCreateManagedWidget("info_area",
2725                                                              xmDrawingAreaWidgetClass,
2726                                                              form2,
2727                                                              XmNheight, 0,
2728                                                              XmNbottomAttachment, XmATTACH_NONE,
2729                                                              XmNtopAttachment, XmATTACH_FORM,
2730                                                              XmNleftAttachment, XmATTACH_FORM,
2731                                                              XmNrightAttachment, XmATTACH_FORM,
2732                                                              XmNmarginHeight, 2,
2733                                                              XmNmarginWidth, 2,
2734                                                              NULL));
2735
2736    p_w->areas[AW_BOTTOM_AREA] =
2737        new AW_area_management(form2, XtVaCreateManagedWidget("bottom_area",
2738                                                              xmDrawingAreaWidgetClass,
2739                                                              form2,
2740                                                              XmNheight, 0,
2741                                                              XmNbottomAttachment, XmATTACH_FORM,
2742                                                              XmNtopAttachment, XmATTACH_NONE,
2743                                                              XmNleftAttachment, XmATTACH_FORM,
2744                                                              XmNrightAttachment, XmATTACH_FORM,
2745                                                              NULL));
2746
2747    p_w->scroll_bar_horizontal = XtVaCreateManagedWidget("scroll_bar_horizontal",
2748                                                         xmScrollBarWidgetClass,
2749                                                         form2,
2750                                                         XmNheight, 15,
2751                                                         XmNminimum, 0,
2752                                                         XmNmaximum, AW_SCROLL_MAX,
2753                                                         XmNincrement, 10,
2754                                                         XmNsliderSize, AW_SCROLL_MAX,
2755                                                         XmNrightAttachment, XmATTACH_FORM,
2756                                                         XmNbottomAttachment, XmATTACH_FORM,
2757                                                         XmNbottomOffset, 0,
2758                                                         XmNleftAttachment, XmATTACH_FORM,
2759                                                         XmNtopAttachment, XmATTACH_NONE,
2760                                                         XmNorientation, XmHORIZONTAL,
2761                                                         XmNrightOffset, 18,
2762                                                         NULL);
2763
2764    p_w->scroll_bar_vertical = XtVaCreateManagedWidget("scroll_bar_vertical",
2765                                                       xmScrollBarWidgetClass,
2766                                                       form2,
2767                                                       XmNwidth, 15,
2768                                                       XmNminimum, 0,
2769                                                       XmNmaximum, AW_SCROLL_MAX,
2770                                                       XmNincrement, 10,
2771                                                       XmNsliderSize, AW_SCROLL_MAX,
2772                                                       XmNrightAttachment, XmATTACH_FORM,
2773                                                       XmNbottomAttachment, XmATTACH_WIDGET,
2774                                                       XmNbottomWidget, p_w->scroll_bar_horizontal,
2775                                                       XmNbottomOffset, 3,
2776                                                       XmNleftOffset, 3,
2777                                                       XmNrightOffset, 3,
2778                                                       XmNleftAttachment, XmATTACH_NONE,
2779                                                       XmNtopAttachment, XmATTACH_WIDGET,
2780                                                       XmNtopWidget, INFO_WIDGET,
2781                                                       NULL);
2782
2783    p_w->frame = XtVaCreateManagedWidget("draw_area",
2784                                         xmFrameWidgetClass,
2785                                         form2,
2786                                         XmNshadowType, XmSHADOW_IN,
2787                                         XmNshadowThickness, 2,
2788                                         XmNleftOffset, 3,
2789                                         XmNtopOffset, 3,
2790                                         XmNbottomOffset, 3,
2791                                         XmNrightOffset, 3,
2792                                         XmNbottomAttachment, XmATTACH_WIDGET,
2793                                         XmNbottomWidget, p_w->scroll_bar_horizontal,
2794                                         XmNtopAttachment, XmATTACH_FORM,
2795                                         XmNtopOffset, 0,
2796                                         XmNleftAttachment, XmATTACH_FORM,
2797                                         XmNrightAttachment, XmATTACH_WIDGET,
2798                                         XmNrightWidget, p_w->scroll_bar_vertical,
2799                                         NULL);
2800
2801    p_w->areas[AW_MIDDLE_AREA] =
2802        new AW_area_management(p_w->frame, XtVaCreateManagedWidget("draw area",
2803                                                                   xmDrawingAreaWidgetClass,
2804                                                                   p_w->frame,
2805                                                                   XmNmarginHeight, 0,
2806                                                                   XmNmarginWidth, 0,
2807                                                                   NULL));
2808
2809    XmMainWindowSetAreas(main_window, p_w->menu_bar[0], (Widget) NULL,
2810                         (Widget) NULL, (Widget) NULL, form1);
2811
2812    aw_realize_widget(this);
2813
2814    create_devices();
2815    aw_insert_default_help_entries(this);
2816    create_window_variables();
2817}
2818
2819void AW_window_simple::init(AW_root *root_in, const char *wid, const char *windowname) {
2820    root = root_in; // for macro
2821
2822    int width  = 100; // this is only the minimum size!
2823    int height = 100;
2824    int posx   = 50;
2825    int posy   = 50;
2826
2827    window_name = strdup(windowname);
2828    window_defaults_name = GBS_string_2_key(wid);
2829
2830    p_w->shell = aw_create_shell(this, true, true, width, height, posx, posy);
2831
2832    // add this to disable resize or maximize in simple dialogs (avoids broken layouts)
2833    // XtVaSetValues(p_w->shell, XmNmwmFunctions, MWM_FUNC_MOVE | MWM_FUNC_CLOSE, NULL);
2834
2835    Widget form1 = XtVaCreateManagedWidget("forms", xmFormWidgetClass,
2836            p_w->shell,
2837            NULL);
2838
2839    p_w->areas[AW_INFO_AREA] =
2840        new AW_area_management(form1, XtVaCreateManagedWidget("info_area",
2841                                                              xmDrawingAreaWidgetClass,
2842                                                              form1,
2843                                                              XmNbottomAttachment, XmATTACH_FORM,
2844                                                              XmNtopAttachment, XmATTACH_FORM,
2845                                                              XmNleftAttachment, XmATTACH_FORM,
2846                                                              XmNrightAttachment, XmATTACH_FORM,
2847                                                              XmNmarginHeight, 2,
2848                                                              XmNmarginWidth, 2,
2849                                                              NULL));
2850
2851    aw_realize_widget(this);
2852    create_devices();
2853}
2854
2855void AW_window_simple_menu::init(AW_root *root_in, const char *wid, const char *windowname) { 
2856    root = root_in; // for macro
2857
2858    const char *help_button = "HELP";
2859    const char *help_mnemonic = "H";
2860    window_name = strdup(windowname);
2861    window_defaults_name = GBS_string_2_key(wid);
2862
2863    int width = 100;
2864    int height = 100;
2865    int posx = 50;
2866    int posy = 50;
2867
2868    p_w->shell = aw_create_shell(this, true, true, width, height, posx, posy);
2869
2870    Widget main_window;
2871    Widget help_popup;
2872    Widget help_label;
2873    Widget form1;
2874
2875    main_window = XtVaCreateManagedWidget("mainWindow1",
2876                                          xmMainWindowWidgetClass, p_w->shell,
2877                                          NULL);
2878
2879    p_w->menu_bar[0] = XtVaCreateManagedWidget("menu1", xmRowColumnWidgetClass,
2880                                               main_window,
2881                                               XmNrowColumnType, XmMENU_BAR,
2882                                               NULL);
2883
2884    // create shell for help-cascade
2885    help_popup = XtVaCreatePopupShell("menu_shell", xmMenuShellWidgetClass,
2886                                      p_w->menu_bar[0],
2887                                      XmNwidth, 1,
2888                                      XmNheight, 1,
2889                                      XmNallowShellResize, true,
2890                                      XmNoverrideRedirect, true,
2891                                      NULL);
2892
2893    // create row column in Pull-Down shell
2894    p_w->help_pull_down = XtVaCreateWidget("menu_row_column",
2895                                           xmRowColumnWidgetClass, help_popup,
2896                                           XmNrowColumnType, XmMENU_PULLDOWN,
2897                                           NULL);
2898
2899    // create HELP-label in menu bar
2900    help_label = XtVaCreateManagedWidget("menu1_top_b1",
2901                                         xmCascadeButtonWidgetClass, p_w->menu_bar[0],
2902                                         RES_CONVERT(XmNlabelString, help_button),
2903                                         RES_CONVERT(XmNmnemonic, help_mnemonic),
2904                                         XmNsubMenuId, p_w->help_pull_down, NULL);
2905    XtVaSetValues(p_w->menu_bar[0], XmNmenuHelpWidget, help_label, NULL);
2906    root->make_sensitive(help_label, AWM_ALL);
2907
2908    form1 = XtVaCreateManagedWidget("form1",
2909                                    xmFormWidgetClass,
2910                                    main_window,
2911                                    XmNtopOffset, 10,
2912                                    XmNresizePolicy, XmRESIZE_NONE,
2913                                    NULL);
2914
2915    p_w->areas[AW_INFO_AREA] =
2916        new AW_area_management(form1, XtVaCreateManagedWidget("info_area",
2917                                                              xmDrawingAreaWidgetClass,
2918                                                              form1,
2919                                                              XmNbottomAttachment, XmATTACH_FORM,
2920                                                              XmNtopAttachment, XmATTACH_FORM,
2921                                                              XmNleftAttachment, XmATTACH_FORM,
2922                                                              XmNrightAttachment, XmATTACH_FORM,
2923                                                              XmNmarginHeight, 2,
2924                                                              XmNmarginWidth, 2,
2925                                                              NULL));
2926
2927    aw_realize_widget(this);
2928
2929    aw_insert_default_help_entries(this);
2930    create_devices();
2931}
2932
2933void AW_window_message::init(AW_root *root_in, const char *wid, const char *windowname, bool allow_close) {
2934    root = root_in; // for macro
2935
2936    int width  = 100;
2937    int height = 100;
2938    int posx   = 50;
2939    int posy   = 50;
2940
2941    window_name          = strdup(windowname);
2942    window_defaults_name = strdup(wid);
2943
2944    // create shell for message box
2945    p_w->shell = aw_create_shell(this, true, allow_close, width, height, posx, posy);
2946
2947    // disable resize or maximize in simple dialogs (avoids broken layouts)
2948    XtVaSetValues(p_w->shell, XmNmwmFunctions, MWM_FUNC_MOVE | MWM_FUNC_CLOSE,
2949            NULL);
2950
2951    p_w->areas[AW_INFO_AREA] =
2952        new AW_area_management(p_w->shell, XtVaCreateManagedWidget("info_area",
2953                                                                   xmDrawingAreaWidgetClass,
2954                                                                   p_w->shell,
2955                                                                   XmNheight, 0,
2956                                                                   XmNbottomAttachment, XmATTACH_NONE,
2957                                                                   XmNtopAttachment, XmATTACH_FORM,
2958                                                                   XmNleftAttachment, XmATTACH_FORM,
2959                                                                   XmNrightAttachment, XmATTACH_FORM,
2960                                                                   NULL));
2961
2962    aw_realize_widget(this);
2963}
2964void AW_window_message::init(AW_root *root_in, const char *windowname, bool allow_close) {
2965    char *wid = GBS_string_2_key(windowname);
2966    init(root_in, wid, windowname, allow_close);
2967    free(wid);
2968}
2969
2970void AW_window::set_focus_policy(bool follow_mouse) {
2971    int focusPolicy = follow_mouse ? XmPOINTER : XmEXPLICIT;
2972    XtVaSetValues(p_w->shell, XmNkeyboardFocusPolicy, focusPolicy, NULL);
2973}
2974
2975void AW_window::select_mode(int mode) {
2976    if (mode >= p_w->number_of_modes)
2977        return;
2978
2979    Widget oldwidget = p_w->modes_widgets[p_w->selected_mode];
2980    p_w->selected_mode = mode;
2981    Widget widget = p_w->modes_widgets[p_w->selected_mode];
2982    XtVaSetValues(oldwidget, XmNbackground, p_global->background, NULL);
2983    XtVaSetValues(widget, XmNbackground, p_global->foreground, NULL);
2984}
2985
2986static void aw_mode_callback(AW_window *aww, short mode, AW_cb *cbs) {
2987    aww->select_mode(mode);
2988    cbs->run_callbacks();
2989}
2990
2991#define MODE_BUTTON_OFFSET 34
2992inline int yoffset_for_mode_button(int button_number) {
2993    return button_number*MODE_BUTTON_OFFSET + (button_number/4)*8 + 2;
2994}
2995
2996int AW_window::create_mode(const char *pixmap, const char *helpText, AW_active mask, const WindowCallback& cb) {
2997    aw_assert(legal_mask(mask));
2998    Widget button;
2999
3000    TuneBackground(p_w->mode_area, TUNE_BUTTON); // set background color for mode-buttons
3001
3002    const char *path = AW_get_pixmapPath(pixmap);
3003
3004    int y = yoffset_for_mode_button(p_w->number_of_modes);
3005    button = XtVaCreateManagedWidget("", xmPushButtonWidgetClass, p_w->mode_area,
3006                                     XmNx,               0,
3007                                     XmNy,               y,
3008                                     XmNlabelType,       XmPIXMAP,
3009                                     XmNshadowThickness, 1,
3010                                     XmNbackground,      _at->background_color,
3011                                     NULL);
3012    XtVaSetValues(button, RES_CONVERT(XmNlabelPixmap, path), NULL);
3013    XtVaGetValues(button, XmNforeground, &p_global->foreground, NULL);
3014
3015    AW_cb *cbs = new AW_cb(this, cb, 0);
3016    AW_cb *cb2 = new AW_cb(this, makeWindowCallback(aw_mode_callback, p_w->number_of_modes, cbs), helpText, cbs);
3017    XtAddCallback(button, XmNactivateCallback,
3018    (XtCallbackProc) AW_server_callback,
3019    (XtPointer) cb2);
3020
3021    if (!p_w->modes_f_callbacks) {
3022        p_w->modes_f_callbacks = (AW_cb **)GB_calloc(sizeof(AW_cb*), AW_NUMBER_OF_F_KEYS); // valgrinders : never freed because AW_window never is freed
3023    }
3024    if (!p_w->modes_widgets) {
3025        p_w->modes_widgets = (Widget *)GB_calloc(sizeof(Widget), AW_NUMBER_OF_F_KEYS);
3026    }
3027    if (p_w->number_of_modes<AW_NUMBER_OF_F_KEYS) {
3028        p_w->modes_f_callbacks[p_w->number_of_modes] = cb2;
3029        p_w->modes_widgets[p_w->number_of_modes] = button;
3030    }
3031
3032    root->make_sensitive(button, mask);
3033    p_w->number_of_modes++;
3034
3035    int ynext = yoffset_for_mode_button(p_w->number_of_modes);
3036    if (ynext> _at->max_y_size) _at->max_y_size = ynext;
3037
3038    return p_w->number_of_modes;
3039}
3040
3041AW_area_management::AW_area_management(Widget formi, Widget widget) {
3042    memset((char *)this, 0, sizeof(AW_area_management));
3043    form = formi;
3044    area = widget;
3045}
3046
3047AW_device_Xm *AW_area_management::get_screen_device() {
3048    if (!device) device = new AW_device_Xm(common);
3049    return device;
3050}
3051
3052AW_device_size *AW_area_management::get_size_device() {
3053    if (!size_device) size_device = new AW_device_size(common);
3054    return size_device;
3055}
3056
3057AW_device_print *AW_area_management::get_print_device() {
3058    if (!print_device) print_device = new AW_device_print(common);
3059    return print_device;
3060}
3061
3062AW_device_click *AW_area_management::get_click_device() {
3063    if (!click_device) click_device = new AW_device_click(common);
3064    return click_device;
3065}
3066
3067void AW_window::wm_activate() {
3068    {
3069        Boolean iconic = False;
3070        XtVaGetValues(p_w->shell, XmNiconic, &iconic, NULL);
3071
3072        if (iconic == True) {
3073            XtVaSetValues(p_w->shell, XmNiconic, False, NULL);
3074
3075            XtMapWidget(p_w->shell);
3076            XRaiseWindow(XtDisplay(p_w->shell), XtWindow(p_w->shell));
3077        }
3078    }
3079
3080    {
3081        Display *xdpy            = XtDisplay(p_w->shell);
3082        Window   window          = XtWindow(p_w->shell);
3083        Atom     netactivewindow = XInternAtom(xdpy, "_NET_ACTIVE_WINDOW", False);
3084
3085        if (netactivewindow) {
3086
3087            XClientMessageEvent ce;
3088            ce.type         = ClientMessage;
3089            ce.display      = xdpy;
3090            ce.window       = window;
3091            ce.message_type = netactivewindow;
3092            ce.format       = 32;
3093            ce.data.l[0]    = 2;
3094            ce.data.l[1]    = None;
3095            ce.data.l[2]    = Above;
3096            ce.data.l[3]    = 0;
3097            ce.data.l[4]    = 0;
3098
3099#if defined(DEBUG)
3100            Status ret =
3101#endif // DEBUG
3102                XSendEvent(xdpy, XDefaultRootWindow(xdpy),
3103                           False,
3104                           SubstructureRedirectMask | SubstructureNotifyMask,
3105                           (XEvent *) &ce);
3106
3107#if defined(DEBUG)
3108            if (!ret) { fprintf(stderr, "Failed to send _NET_ACTIVE_WINDOW to WM (XSendEvent returns %i)\n", ret); }
3109#endif // DEBUG
3110            XSync(xdpy, False);
3111        }
3112#if defined(DEBUG)
3113        else {
3114            fputs("No such atom '_NET_ACTIVE_WINDOW'\n", stderr);
3115        }
3116#endif // DEBUG
3117    }
3118}
3119
3120void AW_window::_set_activate_callback(void *widget) {
3121    if (_callback && (long)_callback != 1) {
3122        if (!_callback->help_text && _at->helptext_for_next_button) {
3123            _callback->help_text = _at->helptext_for_next_button;
3124            _at->helptext_for_next_button = 0;
3125        }
3126
3127        XtAddCallback((Widget) widget, XmNactivateCallback,
3128                (XtCallbackProc) AW_server_callback, (XtPointer) _callback);
3129    }
3130    _callback = NULL;
3131}
3132
3133
3134void AW_window::set_background(const char *colorname, Widget parentWidget) {
3135    bool colorSet = false;
3136
3137    if (colorname) {
3138        XColor unused, color;
3139
3140        if (XAllocNamedColor(p_global->display, p_global->colormap, colorname, &color, &unused)
3141                == 0) {
3142            fprintf(stderr, "XAllocColor failed: %s\n", colorname);
3143        }
3144        else {
3145            _at->background_color = color.pixel;
3146            colorSet = true;
3147        }
3148    }
3149
3150    if (!colorSet) {
3151        XtVaGetValues(parentWidget, XmNbackground, &(_at->background_color),
3152                NULL); // fallback to background color
3153    }
3154}
3155
3156void AW_window::TuneOrSetBackground(Widget w, const char *color, int modStrength) {
3157    // Sets the background for the next created widget.
3158    //
3159    // If 'color' is specified, it may contain one of the following values:
3160    //      "+"    means: slightly increase color of parent widget 'w'
3161    //      "-"    means: slightly decrease color of parent widget 'w'
3162    //      otherwise it contains a specific color ('name' or '#RGB')
3163    //
3164    // If color is not specified, the color of the parent widget 'w' is modified
3165    // by 'modStrength' (increased if positive,  decreased if negative)
3166    //
3167    // If it's not possible to modify the color (e.g. we cannot increase 'white'),
3168    // the color will be modified in the opposite direction. For details see TuneBackground()
3169
3170    if (color) {
3171        switch (color[0]) {
3172        case '+':
3173            TuneBackground(w, TUNE_BRIGHT);
3174            break;
3175        case '-':
3176            TuneBackground(w, TUNE_DARK);
3177            break;
3178        default:
3179            set_background(color, w); // use explicit color
3180        }
3181    }
3182    else {
3183        TuneBackground(w, modStrength);
3184    }
3185}
3186
3187void AW_window::TuneBackground(Widget w, int modStrength) {
3188    // Gets the Background Color, modifies the rgb values slightly and sets new background color
3189    // Intended to give buttons a nicer 3D-look.
3190    //
3191    // possible values for modStrength:
3192    //
3193    //    0        = do not modify (i.e. set to background color of parent widget)
3194    //    1 .. 127 = increase if background is bright, decrease if background is dark
3195    //   -1 ..-127 = opposite behavior than above
3196    //  256 .. 383 = always increase
3197    // -256 ..-383 = always decrease
3198    //
3199    // if it's impossible to decrease or increase -> opposite direction is used.
3200
3201    int col[3];
3202    {
3203        Pixel bg;
3204        XtVaGetValues(w, XmNbackground, &bg, NULL);
3205
3206        XColor xc;
3207        xc.pixel = bg;
3208        XQueryColor(XtDisplay(w), p_global->colormap, &xc);
3209
3210        col[0] = xc.red >> 8; // take MSB
3211        col[1] = xc.green >> 8;
3212        col[2] = xc.blue >> 8;
3213    }
3214
3215    int mod = modStrength;
3216    int preferredDir = 0;
3217    bool invertedMod = false;
3218
3219    if (modStrength>0) {
3220        if (modStrength>255) {
3221            mod -= 256;
3222            preferredDir = 1; // increase preferred
3223        }
3224    }
3225    else {
3226        if (modStrength<-255) {
3227            mod = -modStrength-256;
3228            preferredDir = -1; // decrease preferred
3229        }
3230        else {
3231            invertedMod = true;
3232            mod = -mod;
3233        }
3234    }
3235
3236    aw_assert(mod >= 0 && mod < 128);
3237    // illegal modification
3238
3239    bool incPossible[3]; // increment possible for color
3240    bool decPossible[3]; // decrement possible for color
3241    int incs = 0; // count possible increments
3242    int decs = 0; // count possible decrements
3243
3244    for (int i = 0; i<3; ++i) {
3245        if ((incPossible[i] = ((col[i]+mod) <= 255)))
3246            incs++;
3247        if ((decPossible[i] = ((col[i]-mod) >= 0)))
3248            decs++;
3249    }
3250
3251    aw_assert(incs||decs);
3252
3253    switch (preferredDir) {
3254    case 0: // no direction preferred yet, need to decide
3255        if (invertedMod)
3256            preferredDir = decs ? -1 : 1;
3257        else
3258            preferredDir = incs ? 1 : -1;
3259        break;
3260    case 1:
3261        if (!incs)
3262            preferredDir = -1;
3263        break;
3264    case -1:
3265        if (!decs)
3266            preferredDir = 1;
3267        break;
3268    }
3269
3270    aw_assert(preferredDir == 1 || preferredDir == -1); // no direction chosen above
3271
3272    if (preferredDir == 1) {
3273        for (int i=0; i<3; ++i) col[i] += (incPossible[i] ? mod : 0);
3274    }
3275    else if (preferredDir == -1) {
3276        for (int i=0; i<3; ++i) col[i] -= (decPossible[i] ? mod : 0);
3277    }
3278
3279
3280    char hex_color[50];
3281    sprintf(hex_color, "#%2.2X%2.2X%2.2X", col[0], col[1], col[2]);
3282    aw_assert(strlen(hex_color) == 7);
3283    // otherwise some value overflowed
3284    set_background(hex_color, w);
3285}
3286
3287void AW_root::make_sensitive(Widget w, AW_active mask) {
3288    // Don't call make_sensitive directly!
3289    //
3290    // Simply set sens_mask(AWM_EXP) and after creating the expert-mode-only widgets,
3291    // set it back using sens_mask(AWM_ALL)
3292
3293    aw_assert(w);
3294    aw_assert(legal_mask(mask));
3295
3296    prvt->set_last_widget(w);
3297
3298    if (mask != AWM_ALL) { // no need to make widget sensitive, if its shown unconditionally
3299        button_sens_list = new AW_buttons_struct(mask, w, button_sens_list);
3300        if (!(mask & global_mask)) XtSetSensitive(w, False); // disable widget if mask doesn't match
3301    }
3302}
3303
3304AW_buttons_struct::AW_buttons_struct(AW_active maski, Widget w, AW_buttons_struct *prev_button) {
3305    aw_assert(w);
3306    aw_assert(legal_mask(maski));
3307
3308    mask     = maski;
3309    button   = w;
3310    next     = prev_button;
3311}
3312
3313AW_buttons_struct::~AW_buttons_struct() {
3314    delete next;
3315}
3316
3317bool AW_root::remove_button_from_sens_list(Widget button) {
3318    bool removed = false;
3319    if (button_sens_list) {
3320        AW_buttons_struct *prev = 0;
3321        AW_buttons_struct *bl   = button_sens_list;
3322
3323        while (bl) {
3324            if (bl->button == button) break; // found wanted widget
3325            prev = bl;
3326            bl = bl->next;
3327        }
3328
3329        if (bl) {
3330            // remove from list
3331            if (prev) prev->next  = bl->next;
3332            else button_sens_list = bl->next;
3333
3334            bl->next = 0;
3335            removed  = true;
3336
3337            delete bl;
3338        }
3339    }
3340    return removed;
3341}
3342
3343AW_option_menu_struct::AW_option_menu_struct(int numberi, const char *variable_namei,
3344                                             AW_VARIABLE_TYPE variable_typei, Widget label_widgeti,
3345                                             Widget menu_widgeti, AW_pos xi, AW_pos yi, int correct) {
3346    option_menu_number = numberi;
3347    variable_name      = strdup(variable_namei);
3348    variable_type      = variable_typei;
3349    label_widget       = label_widgeti;
3350    menu_widget        = menu_widgeti;
3351    first_choice       = NULL;
3352    last_choice        = NULL;
3353    default_choice     = NULL;
3354    next               = NULL;
3355    x                  = xi;
3356    y                  = yi;
3357
3358    correct_for_at_center_intern = correct;
3359}
3360
3361AW_toggle_field_struct::AW_toggle_field_struct(int toggle_field_numberi,
3362        const char *variable_namei, AW_VARIABLE_TYPE variable_typei,
3363        Widget label_widgeti, int correct) {
3364
3365    toggle_field_number = toggle_field_numberi;
3366    variable_name = strdup(variable_namei);
3367    variable_type = variable_typei;
3368    label_widget = label_widgeti;
3369    first_toggle = NULL;
3370    last_toggle = NULL;
3371    default_toggle = NULL;
3372    next = NULL;
3373    correct_for_at_center_intern = correct;
3374}
3375
3376AW_window_Motif::AW_window_Motif()
3377    : shell(0),
3378      scroll_bar_vertical(0),
3379      scroll_bar_horizontal(0),
3380      menu_deep(0),
3381      help_pull_down(0),
3382      mode_area(0),
3383      number_of_modes(0),
3384      modes_f_callbacks(NULL),
3385      modes_widgets(NULL),
3386      selected_mode(0),
3387      popup_cb(NULL),
3388      frame(0),
3389      toggle_field(0),
3390      toggle_label(0),
3391      toggle_field_var_name(NULL),
3392      toggle_field_var_type(AW_NONE),
3393      keymodifier(AW_KEYMODE_NONE),
3394      WM_top_offset(0),
3395      WM_left_offset(0)
3396{
3397    for (int i = 0; i<AW_MAX_MENU_DEEP; ++i) {
3398        menu_bar[i] = 0;
3399    }
3400    for (int i = 0; i<AW_MAX_AREA; ++i) {
3401        areas[i] = NULL;
3402    }
3403}
3404
3405int AW_window_Motif::WM_max_top_offset  = 0;
3406int AW_window_Motif::WM_max_left_offset = 0;
Note: See TracBrowser for help on using the repository browser.