source: branches/species/WINDOW/AW_window.cxx

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