source: branches/properties/WINDOW/AW_window.cxx

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