source: branches/profile/WINDOW/AW_window.cxx

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