source: branches/stable/WINDOW/AW_window.cxx

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