2 * Grace - GRaphing, Advanced Computation and Exploration of data
4 * Home page: http://plasma-gate.weizmann.ac.il/Grace/
6 * Copyright (c) 1991-1995 Paul J Turner, Portland, OR
7 * Copyright (c) 1996-2005 Grace Development Team
9 * Maintained by Evgeny Stambulchik
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
31 * Main Motif interface
42 #include <Xm/RowColumn.h>
43 #include <Xm/ScrolledW.h>
44 #include <Xm/DrawingA.h>
45 #include <Xm/RepType.h>
47 #if defined(HAVE_XPM_H)
54 # include <X11/Xmu/Editres.h>
61 #include "core_utils.h"
73 * establish resource stuff
80 Boolean instantupdate
;
81 } ApplicationData
, *ApplicationDataPtr
;
83 static XtResource resources
[] =
85 {"invertDraw", "InvertDraw", XtRBoolean
, sizeof(Boolean
),
86 XtOffset(ApplicationDataPtr
, invert
), XtRImmediate
,
88 {"toolBar", "ToolBar", XtRBoolean
, sizeof(Boolean
),
89 XtOffset(ApplicationDataPtr
, toolbar
), XtRImmediate
,
91 {"statusBar", "StatusBar", XtRBoolean
, sizeof(Boolean
),
92 XtOffset(ApplicationDataPtr
, statusbar
), XtRImmediate
,
94 {"locatorBar", "LocatorBar", XtRBoolean
, sizeof(Boolean
),
95 XtOffset(ApplicationDataPtr
, locatorbar
), XtRImmediate
,
97 {"instantUpdate", "InstantUpdate", XtRBoolean
, sizeof(Boolean
),
98 XtOffset(ApplicationDataPtr
, instantupdate
), XtRImmediate
,
102 String fallbackResourcesCommon
[] = {
103 "XmGrace.consoleDialog*text.columns: 72",
104 "XmGrace.consoleDialog*text.rows: 5",
105 "XmGrace*background: #e5e5e5",
106 "XmGrace*foreground: #000000",
107 "XmGrace*XbaeMatrix.allowColumnResize: False",
108 "XmGrace*XbaeMatrix.allowRowResize: False",
109 "XmGrace*XbaeMatrix.oddRowBackground: #cccccc",
110 "XmGrace*XbaeMatrix.evenRowBackground: #cfe7e7",
111 "XmGrace*XbaeMatrix.textBackground: #cfe7e7",
112 "XmGrace*XbaeMatrix.selectedBackground: #e5ffff",
113 "XmGrace*XbaeMatrix.selectedForeground: #000000",
114 "XmGrace*fontTable.evenRowBackground: #e5e5e5",
115 "XmGrace*SSD.evenRowBackground: #ffffff",
116 "XmGrace*SSD.buttonLabelBackground: #cccccc",
117 "XmGrace*XmPushButton.background: #b0c4de",
118 "XmGrace*XmMenuShell*XmPushButton.background: #e5e5e5",
119 "XmGrace*penButton.background: #e5e5e5",
120 "XmGrace*XmText*background: #cfe7e7",
121 "XmGrace*XmToggleButton.selectColor: #ff0000",
122 "XmGrace*XmToggleButton.fillOnSelect: true",
123 "XmGrace*XmSeparator.margin: 0",
124 "XmGrace*XmSash.HighlightColor: #b0c4de",
126 "XmGrace*XmHTML.background: #ffffff",
127 "XmGrace*XmHTML.foreground: #000000",
128 "XmGrace*XmHTML.width: 600",
129 "XmGrace*XmHTML.height: 500",
131 "XmGrace*enableThinThickness: True",
132 "XmGrace*mainWin.shadowThickness: 0",
133 "XmGrace*XmMenuShell*shadowThickness: 2",
134 "XmGrace*menuBar*tearOffModel: XmTEAR_OFF_ENABLED",
138 String fallbackResourcesHighRes
[] = {
139 "XmGrace*mainWin.width: 780",
140 "XmGrace*mainWin.height: 660",
141 "XmGrace*explorerDialog.form.width: 650",
142 "XmGrace*explorerDialog.form.height: 600",
143 "XmGrace*fontList:-*-helvetica-medium-r-normal-*-12-*-*-*-*-*-*-*",
144 "XmGrace.consoleDialog*text.fontList:-*-courier-medium-r-normal-*-12-*-*-*-*-*-*-*",
145 "XmGrace*ListTree.font:-*-helvetica-medium-r-normal-*-12-*-*-*-*-*-*-*",
146 "XmGrace*HContainer.marginHeight: 3",
147 "XmGrace*VContainer.marginHeight: 3",
151 String fallbackResourcesLowRes
[] = {
152 "XmGrace*mainWin.width: 600",
153 "XmGrace*mainWin.height: 520",
154 "XmGrace*explorerDialog.form.width: 530",
155 "XmGrace*explorerDialog.form.height: 485",
156 "XmGrace*fontList:-*-helvetica-medium-r-normal-*-8-*-*-*-*-*-*-*",
157 "XmGrace.consoleDialog*text.fontList:-*-courier-medium-r-normal-*-8-*-*-*-*-*-*-*",
158 "XmGrace*ListTree.font:-*-helvetica-medium-r-normal-*-8-*-*-*-*-*-*-*",
159 "XmGrace*HContainer.marginHeight: 1",
160 "XmGrace*VContainer.marginHeight: 1",
164 #ifdef HAVE__XMVERSIONSTRING
165 extern const char _XmVersionString
[];
168 static int is_motif_compatible(void)
172 #ifdef HAVE__XMVERSIONSTRING
177 /* First, check for compatible version */
178 if (xmUseVersion
< XmVersion
) {
180 "Run-time Motif library is older than the build, %d < %d",
181 xmUseVersion
, XmVersion
);
186 bd_lesstif
= (strstr(bi_gui(), "Motif") == NULL
);
188 #ifdef HAVE__XMVERSIONSTRING
189 /* Then, check whether we are in the Motif/LessTif binary compatibility
191 /* strcpy is dangerous since the sizeof(_XmVersionString) may be different
192 at run time! 13 chars should be safe, though, and enough to distinguish
193 between Motif and LessTif :) */
194 strncpy(buf
, _XmVersionString
, 13);
196 rt_lesstif
= (strstr(buf
, "Motif") == NULL
);
197 if (bd_lesstif
!= rt_lesstif
) {
198 sprintf(buf
, "The software was built with %s, but is running with %s!",
199 bd_lesstif
? "LessTif":"Motif", rt_lesstif
? "LessTif":"Motif");
201 errmsg("We don't support binary Motif/LessTif compatibility.");
202 errmsg("Use a semistatic binary or compile Grace yourself!");
206 /* Finally, if LessTif is used, check for a reasonably new release */
208 s
= strstr(_XmVersionString
, "Version");
209 if (s
== NULL
|| (strcmp(s
, "Version 0.90.0") < 0)) {
210 errmsg("An old version of LessTif, please upgrade to 0.90.0 at least");
215 #if XbaeVersion >= 40800
216 /* Now we should compare whether Xbae was built against the
217 runtime version of M*tif/LessTif. */
218 strncpy(buf
, XbaeGetXmVersionTxt(), 13);
220 rt_lesstif
= (strstr(buf
, "Motif") == NULL
);
221 if (bd_lesstif
!= rt_lesstif
) {
222 sprintf(buf
, "libXbae was built with %s, but is running with %s!",
223 bd_lesstif
? "LessTif":"Motif", rt_lesstif
? "LessTif":"Motif");
225 errmsg("Use a semistatic binary or compile Grace/libXbae yourself!");
228 /* Now we check for consistency of the used M*tif version */
229 if (XbaeGetXmVersionNum() != XmVersion
) {
230 sprintf(buf
, "libXbae was built with Motif/LessTif %i, but is running with %i!",
231 XbaeGetXmVersionNum(), XmVersion
);
233 errmsg("Use a semistatic binary or compile Grace/libXbae yourself!");
236 #endif /* XbaeVersion > 40800 */
241 int initialize_gui(int *argc
, char **argv
)
247 String
*allResources
, *resolResources
;
249 unsigned int i
, n_common
, n_resol
;
250 char *display_name
= NULL
;
252 xstuff
= xmalloc(sizeof(X11Stuff
));
253 memset(xstuff
, 0, sizeof(X11Stuff
));
254 gapp
->gui
->xstuff
= xstuff
;
256 mwui
= xmalloc(sizeof(MainWinUI
));
257 memset(mwui
, 0, sizeof(MainWinUI
));
258 gapp
->gui
->mwui
= mwui
;
260 installXErrorHandler();
262 /* Locale settings for GUI */
263 if (!is_locale_utf8()) {
264 XtSetLanguageProc(NULL
, NULL
, NULL
);
267 XtToolkitInitialize();
268 app_con
= XtCreateApplicationContext();
270 /* Check if we're running in the low-resolution X */
271 for (i
= 1; i
< *argc
- 1; i
++) {
272 /* See if display name was specified in the args */
273 char *pattern
= "-display";
274 if (strlen(argv
[i
]) > 1 && strstr(pattern
, argv
[i
]) == pattern
) {
275 display_name
= argv
[i
+ 1];
278 xstuff
->disp
= XOpenDisplay(display_name
);
279 if (xstuff
->disp
== NULL
) {
280 errmsg("Can't open display");
281 return RETURN_FAILURE
;
284 screen
= DefaultScreenOfDisplay(xstuff
->disp
);
285 if (HeightOfScreen(screen
) < 740) {
289 n_common
= sizeof(fallbackResourcesCommon
)/sizeof(String
) - 1;
291 n_resol
= sizeof(fallbackResourcesLowRes
)/sizeof(String
) - 1;
292 resolResources
= fallbackResourcesLowRes
;
294 n_resol
= sizeof(fallbackResourcesHighRes
)/sizeof(String
) - 1;
295 resolResources
= fallbackResourcesHighRes
;
297 allResources
= xmalloc((n_common
+ n_resol
+ 1)*sizeof(String
));
298 for (i
= 0; i
< n_common
; i
++) {
299 allResources
[i
] = fallbackResourcesCommon
[i
];
301 for (i
= 0; i
< n_resol
; i
++) {
302 allResources
[n_common
+ i
] = resolResources
[i
];
304 allResources
[n_common
+ n_resol
] = NULL
;
305 XtAppSetFallbackResources(app_con
, allResources
);
307 XtDisplayInitialize(app_con
, xstuff
->disp
, "xmgrace", "XmGrace", NULL
, 0, argc
, argv
);
309 /* Widget translations etc */
312 app_shell
= XtAppCreateShell(NULL
, "XmGrace", applicationShellWidgetClass
,
313 xstuff
->disp
, NULL
, 0);
315 if (is_motif_compatible() != TRUE
) {
316 return RETURN_FAILURE
;
319 XtGetApplicationResources(app_shell
, &rd
,
320 resources
, XtNumber(resources
), NULL
, 0);
322 gapp
->gui
->invert
= rd
.invert
;
323 gapp
->gui
->instant_update
= rd
.instantupdate
;
324 gapp
->gui
->toolbar
= rd
.toolbar
;
325 gapp
->gui
->statusbar
= rd
.statusbar
;
326 gapp
->gui
->locbar
= rd
.locatorbar
;
330 /* initialize cursors */
331 init_cursors(gapp
->gui
);
333 return RETURN_SUCCESS
;
337 * set visibility of the toolbars
339 void set_view_items(void)
341 MainWinUI
*mwui
= gapp
->gui
->mwui
;
343 if (gapp
->gui
->statusbar
) {
344 SetToggleButtonState(mwui
->windowbarw
[1], TRUE
);
345 WidgetManage(mwui
->frbot
);
346 XtVaSetValues(mwui
->drawing_window
,
347 XmNbottomAttachment
, XmATTACH_WIDGET
,
348 XmNbottomWidget
, mwui
->frbot
,
350 if (gapp
->gui
->toolbar
) {
351 XtVaSetValues(mwui
->frleft
,
352 XmNbottomAttachment
, XmATTACH_WIDGET
,
353 XmNbottomWidget
, mwui
->frbot
,
357 SetToggleButtonState(mwui
->windowbarw
[1], FALSE
);
358 XtVaSetValues(mwui
->drawing_window
,
359 XmNbottomAttachment
, XmATTACH_FORM
,
361 WidgetUnmanage(mwui
->frbot
);
362 if (gapp
->gui
->toolbar
) {
363 XtVaSetValues(mwui
->frleft
,
364 XmNbottomAttachment
, XmATTACH_FORM
,
368 if (gapp
->gui
->toolbar
) {
369 SetToggleButtonState(mwui
->windowbarw
[2], TRUE
);
370 WidgetManage(mwui
->frleft
);
371 if (gapp
->gui
->statusbar
) {
372 XtVaSetValues(mwui
->frleft
,
373 XmNbottomAttachment
, XmATTACH_WIDGET
,
374 XmNbottomWidget
, mwui
->frbot
,
377 if (gapp
->gui
->locbar
) {
378 XtVaSetValues(mwui
->frleft
,
379 XmNtopAttachment
, XmATTACH_WIDGET
,
380 XmNtopWidget
, mwui
->frtop
,
383 XtVaSetValues(mwui
->drawing_window
,
384 XmNleftAttachment
, XmATTACH_WIDGET
,
385 XmNleftWidget
, mwui
->frleft
,
388 SetToggleButtonState(mwui
->windowbarw
[2], FALSE
);
389 WidgetUnmanage(mwui
->frleft
);
390 XtVaSetValues(mwui
->drawing_window
,
391 XmNleftAttachment
, XmATTACH_FORM
,
394 if (gapp
->gui
->locbar
) {
395 SetToggleButtonState(mwui
->windowbarw
[0], TRUE
);
396 WidgetManage(mwui
->frtop
);
397 XtVaSetValues(mwui
->drawing_window
,
398 XmNtopAttachment
, XmATTACH_WIDGET
,
399 XmNtopWidget
, mwui
->frtop
,
401 if (gapp
->gui
->toolbar
) {
402 XtVaSetValues(mwui
->frleft
,
403 XmNtopAttachment
, XmATTACH_WIDGET
,
404 XmNtopWidget
, mwui
->frtop
,
408 SetToggleButtonState(mwui
->windowbarw
[0], FALSE
);
409 WidgetUnmanage(mwui
->frtop
);
410 XtVaSetValues(mwui
->drawing_window
,
411 XmNtopAttachment
, XmATTACH_FORM
,
413 if (gapp
->gui
->toolbar
) {
414 XtVaSetValues(mwui
->frleft
,
415 XmNtopAttachment
, XmATTACH_FORM
,
421 static void canvas_event_proc(Widget w
, XtPointer data
, XEvent
*event
, Boolean
*cont
)
429 cevent
.modifiers
= NO_MODIFIER
;
430 cevent
.button
= NO_BUTTON
;
431 cevent
.key
= KEY_NONE
;
432 cevent
.x
= event
->xmotion
.x
;
433 cevent
.y
= event
->xmotion
.y
;
435 switch (event
->type
) {
437 cevent
.type
= MOUSE_MOVE
;
438 xme
= (XMotionEvent
*) event
;
439 if (xme
->state
& Button1Mask
) {
440 cevent
.button
= cevent
.button
^ LEFT_BUTTON
;
442 if (xme
->state
& ControlMask
) {
443 cevent
.modifiers
= cevent
.modifiers
^ CONTROL_MODIFIER
;
447 cevent
.type
= MOUSE_PRESS
;
448 xbe
= (XButtonEvent
*) event
;
450 cevent
.x
= event
->xbutton
.x
;
451 cevent
.y
= event
->xbutton
.y
;
452 switch (event
->xbutton
.button
) {
454 cevent
.button
= cevent
.button
^ LEFT_BUTTON
;
455 cevent
.time
= xbe
->time
;
458 cevent
.button
= cevent
.button
^ MIDDLE_BUTTON
;
461 cevent
.button
= cevent
.button
^ RIGHT_BUTTON
;
464 cevent
.button
= cevent
.button
^ WHEEL_UP_BUTTON
;
467 cevent
.button
= cevent
.button
^ WHEEL_DOWN_BUTTON
;
470 if (xbe
->state
& ControlMask
) {
471 cevent
.modifiers
= cevent
.modifiers
^ CONTROL_MODIFIER
;
475 cevent
.type
= MOUSE_RELEASE
;
476 xbe
= (XButtonEvent
*) event
;
477 switch (event
->xbutton
.button
) {
479 cevent
.button
= cevent
.button
^ LEFT_BUTTON
;
482 if (xbe
->state
& ControlMask
) {
483 cevent
.modifiers
= cevent
.modifiers
^ CONTROL_MODIFIER
;
487 cevent
.type
= KEY_PRESS
;
488 xke
= (XKeyEvent
*) event
;
489 keybuf
= XLookupKeysym(xke
, 0);
491 case XK_Escape
: /* Esc */
492 cevent
.key
= KEY_ESCAPE
;
494 case XK_KP_Add
: /* "Grey" plus */
495 cevent
.key
= KEY_PLUS
;
497 case XK_KP_Subtract
: /* "Grey" minus */
498 cevent
.key
= KEY_MINUS
;
504 if (xke
->state
& ControlMask
) {
505 cevent
.modifiers
= cevent
.modifiers
^ CONTROL_MODIFIER
;
509 cevent
.type
= KEY_RELEASE
;
510 xke
= (XKeyEvent
*) event
;
511 if (xke
->state
& ControlMask
) {
512 cevent
.modifiers
= cevent
.modifiers
^ CONTROL_MODIFIER
;
519 canvas_event(&cevent
);
525 void startup_gui(GraceApp
*gapp
)
527 MainWinUI
*mwui
= gapp
->gui
->mwui
;
528 X11Stuff
*xstuff
= gapp
->gui
->xstuff
;
529 Widget main_frame
, form
, menu_bar
, rcleft
;
533 * Allow users to change tear off menus with X resources
535 XmRepTypeInstallTearOffModelConverter();
538 XtAddEventHandler(app_shell
, (EventMask
) 0, True
, _XEditResCheckMessages
, NULL
);
542 * We handle important WM events ourselves
544 handle_close(app_shell
);
546 XtVaSetValues(app_shell
, XmNcolormap
, xstuff
->cmap
, NULL
);
551 main_frame
= XtVaCreateManagedWidget("mainWin",
552 xmMainWindowWidgetClass
, app_shell
, NULL
);
554 menu_bar
= CreateMainMenuBar(main_frame
);
555 WidgetManage(menu_bar
);
557 form
= CreateForm(main_frame
);
559 mwui
->frleft
= CreateFrame(form
, NULL
);
560 rcleft
= XtVaCreateManagedWidget("toolBar", xmRowColumnWidgetClass
,
562 XmNorientation
, XmVERTICAL
,
563 XmNpacking
, XmPACK_TIGHT
,
570 mwui
->frtop
= CreateFrame(form
, NULL
);
571 mwui
->loclab
= CreateLabel(mwui
->frtop
, NULL
);
573 mwui
->frbot
= CreateFrame(form
, NULL
);
574 mwui
->statlab
= CreateLabel(mwui
->frbot
, NULL
);
576 if (!gui_is_page_free(gapp
->gui
)) {
577 mwui
->drawing_window
= XtVaCreateManagedWidget("drawing_window",
578 xmScrolledWindowWidgetClass
, form
,
579 XmNscrollingPolicy
, XmAUTOMATIC
,
580 XmNvisualPolicy
, XmVARIABLE
,
582 xstuff
->canvas
= XtVaCreateManagedWidget("canvas",
583 xmDrawingAreaWidgetClass
,
584 mwui
->drawing_window
,
587 xstuff
->canvas
= XtVaCreateManagedWidget("canvas",
588 xmDrawingAreaWidgetClass
, form
,
590 mwui
->drawing_window
= xstuff
->canvas
;
593 XtAddCallback(xstuff
->canvas
, XmNexposeCallback
, expose_resize
, gapp
);
594 XtAddCallback(xstuff
->canvas
, XmNresizeCallback
, expose_resize
, gapp
);
596 XtAddEventHandler(xstuff
->canvas
,
602 | ColormapChangeMask
,
604 canvas_event_proc
, gapp
);
606 AddHelpCB(xstuff
->canvas
, "doc/UsersGuide.html#canvas");
608 XtVaSetValues(mwui
->frtop
,
609 XmNtopAttachment
, XmATTACH_FORM
,
610 XmNleftAttachment
, XmATTACH_FORM
,
611 XmNrightAttachment
, XmATTACH_FORM
,
613 XtVaSetValues(mwui
->frbot
,
614 XmNbottomAttachment
, XmATTACH_FORM
,
615 XmNrightAttachment
, XmATTACH_FORM
,
616 XmNleftAttachment
, XmATTACH_FORM
,
618 XtVaSetValues(mwui
->frleft
,
619 XmNtopAttachment
, XmATTACH_WIDGET
,
620 XmNtopWidget
, mwui
->frtop
,
621 XmNbottomAttachment
, XmATTACH_WIDGET
,
622 XmNbottomWidget
, mwui
->frbot
,
623 XmNleftAttachment
, XmATTACH_FORM
,
625 XtVaSetValues(mwui
->drawing_window
,
626 XmNtopAttachment
, XmATTACH_WIDGET
,
627 XmNtopWidget
, mwui
->frtop
,
628 XmNbottomAttachment
, XmATTACH_WIDGET
,
629 XmNbottomWidget
, mwui
->frbot
,
630 XmNleftAttachment
, XmATTACH_WIDGET
,
631 XmNleftWidget
, mwui
->frleft
,
632 XmNrightAttachment
, XmATTACH_FORM
,
637 XmMainWindowSetAreas(main_frame
, menu_bar
, NULL
, NULL
, NULL
, form
);
639 CreateToolBar(rcleft
);
641 * initialize some option menus
646 * initialize the tool bars
650 set_tracker_string(NULL
);
651 set_left_footer(NULL
);
656 XpmCreatePixmapFromData(xstuff
->disp
, xstuff
->root
,
657 gapp_icon_xpm
, &icon
, &shape
, NULL
);
658 XtVaSetValues(app_shell
, XtNiconPixmap
, icon
, XtNiconMask
, shape
, NULL
);
660 XtRealizeWidget(app_shell
);
662 XmProcessTraversal(xstuff
->canvas
, XmTRAVERSE_CURRENT
);
664 xstuff
->xwin
= XtWindow(xstuff
->canvas
);
665 gapp
->gui
->inwin
= TRUE
;
670 update_app_title(gapp
->gp
);
672 XtAppMainLoop(app_con
);