Menu.c: #include <stdio.h> #include <X11/X.h> #include <X11/Xlib.h> #include <X11/Intrinsic.h> #include <Xm/MainW.h> #include <Xm/RowColumn.h> #include <Xm/TextF.h> void file_pulldown_cb(w, data, event ) Widget w; int data; XtPointer event; { fprintf ( stdout, "data = %d\n", data ); if (data == 5 ) exit(0); } main(argc, argv) int argc; char *argv[]; { XtAppContext app; Widget toplevel_shell, main_window, canvas_field, top_menubar, file_pulldown; XmString file, new, new_acc, open, open_acc, save, save_acc, saveas, close, quit, quit_acc; toplevel_shell = XtVaAppInitialize(&app, "Menus", NULL, 0, &argc, argv, NULL, NULL); main_window = XtVaCreateManagedWidget("main_window", xmMainWindowWidgetClass, toplevel_shell, NULL); file = XmStringCreateSimple("File"); top_menubar = XmVaCreateSimpleMenuBar(main_window, "top_menubar", XmVaCASCADEBUTTON, file, 'F', NULL ); XmStringFree(file); new = XmStringCreateSimple("New"); new_acc = XmStringCreateSimple("Ctrl+N"); open = XmStringCreateSimple("Open..."); open_acc = XmStringCreateSimple("Ctrl+O"); save = XmStringCreateSimple("Save"); save_acc = XmStringCreateSimple("Ctrl+S"); saveas = XmStringCreateSimple("Save As..."); close = XmStringCreateSimple("Close"); quit = XmStringCreateSimple("Quit"); quit_acc = XmStringCreateSimple("Ctrl+C"); file_pulldown = XmVaCreateSimplePulldownMenu(top_menubar, "file_pulldown", 0, file_pulldown_cb, XmVaPUSHBUTTON, new, 'N', "Ctrl<Key> n", new_acc, XmVaPUSHBUTTON, open, 'O', "Ctrl<Key> o", open_acc, XmVaPUSHBUTTON, save, 'S', "Ctrl<Key> s", save_acc, XmVaPUSHBUTTON, saveas, 'A', NULL, NULL, XmVaSEPARATOR, XmVaPUSHBUTTON, close, 'C', NULL, NULL, XmVaPUSHBUTTON, quit, 'Q', "Ctrl<Key> c", quit_acc, NULL ); XmStringFree(new); XmStringFree(new_acc); XmStringFree(open); XmStringFree(save); XmStringFree(saveas); XmStringFree(close); XmStringFree(quit); XmStringFree(new_acc); XmStringFree(open_acc); XmStringFree(save_acc); XmStringFree(quit_acc); XtManageChild(top_menubar); XtRealizeWidget(toplevel_shell); XtAppMainLoop(app); }
See Part One of this workshop www page for an example of how to compile the source code.
The menubar is created using the XmVaCreateSimpleMenuBar() function. The returned widget must be managed with XtManageChild().
Another function is used to make pulldown menus inside the menubar - XmVaCreateSimplePulldownMenu().
The variable argument functions used have a set of arguments defined which can be used to specify of what class we want the child widgets to be. (XmVaCASCADEBUTTON, XmVaPUSHBUTTON etc. ) This is instead of creating each sub-widget explicitly with a seperate function.
Experiment with the menu program - try adding more pulldown menus so that you get a menu like those seen is full blown applications.
Project Edit Open... Cut Save Copy Save as... Paste Print... Quit
Popup.c: #include <X11/StringDefs.h> #include <Xm/Xm.h> #include <Xm/PushB.h> Widget toplevel; void close_window(w, client_data, event_data) { Widget popup = (Widget)client_data; XtPopdown(popup); XtDestroyWidget(popup); } void pop(w, client_data, event_data) Widget w; XtPointer client_data; XtPointer event_data; { Widget a, button, popup; popup = XtVaCreatePopupShell("Popup", transientShellWidgetClass, toplevel, NULL); button = XtVaCreateManagedWidget("Close", xmPushButtonWidgetClass, popup, NULL); XtAddCallback(button, XmNactivateCallback, close_window, (XtPointer)popup); XtPopup(popup, XtGrabNone); } main(argc, argv) int argc; char *argv[]; { Widget button; XtAppContext app; XmString label; toplevel = XtVaAppInitialize(&app, "Popup", NULL, 0, &argc, argv, NULL, NULL); label = XmStringCreateSimple("Make popup"); button = XtVaCreateManagedWidget("pushme", xmPushButtonWidgetClass, toplevel, XmNlabelString, label, NULL); XmStringFree(label); XtAddCallback(button, XmNactivateCallback, pop, NULL); XtRealizeWidget(toplevel); XtAppMainLoop(app); }
The popups are created with the toplevel shell widget as the parent. This means that if you iconize the toplevel shell, then all associated popup windows will also iconize.
The line that actually causes the popup-window to be displayed is:
XtPopup(popup, XtGrabNone);If XtGrabNone is changed to "XtGrabExclusive", then that window is made to be the only one that accepts events and you won't be able to press the "make popup" button on the main shell window until you have closed the popup. This is useful for getting information from the user before the application can proceed e.g. getting a save filename before saving a file.
draw.c: #include <X11/StringDefs.h> #include <Xm/Xm.h> #include <Xm/DrawingA.h> void redraw(w, calldata, ev) Widget w; XtPointer calldata; XtPointer ev; { GC gc = (GC)calldata; Window win = XtWindow(w); Display *d = XtDisplay(w); XDrawLine(d, win, gc, 0, 0, 150, 150); XDrawRectangle(d, win, gc, 150, 150, 200, 100); XFillRectangle(d, win, gc, 200, 200, 100, 50); } main(argc, argv) int argc; char *argv[]; { Widget toplevel, viewport; XGCValues values; GC gc; XtAppContext appcon; toplevel = XtVaAppInitialize(&appcon, "Draw", NULL, 0, &argc, argv, NULL, 0); viewport = XtVaCreateManagedWidget("viewport", xmDrawingAreaWidgetClass, toplevel, XmNwidth, 400, XmNheight, 300, NULL); XtVaGetValues(viewport, XtNforeground, &values.foreground, XtNbackground, &values.background, NULL); gc = XtGetGC(viewport, GCForeground | GCBackground, &values); XtAddEventHandler(viewport, ButtonPressMask , FALSE, redraw, (XtPointer)gc); XtRealizeWidget(toplevel); XtAppMainLoop(appcon); }
Notice that, if another window is dragged over this one, the drawing is lost. Refresh the window by clicking in the window once again.
The button-press is detected by the event-handler "XtAddEventHandler()". This tells the application to call the redraw function whenever a button is pressed in the viewport widget.
Event-handlers work in the same way as callbacks but allow the programmer to specify the exact event to react to. The event-masks can be added together so that one event handler can wait for more than one different event type (e.g. if the programmer wanted to watch for mouse-button presses AND key-presses - "KeyPressMask | ButtonPressMask" would be used.
(for a full list of event-masks, see the Event Definitions in /usr/include/X11/X.h).
It is up to the application to refresh the picture when it needs to be redrawn. This can be done by watching for expose events. Expose events occur when parts of the window get corrupted.
Change "ButtonPressMask" to "ExposureMask" - this will tell the application to automatically draw into the window every time it needs to.
Three XLib functions are used in this program XDrawLine, XDrawRectangle, XFillRectangle. All of these functions use the same first three parameters.
The first parameter is the display - this is a handle to the X-display to use. Normally this is not referenced from Xt but for use with XLib functions, it can be retrieved by using XtDisplay on a widget.
Widgets are built from lower-level XLib Windows. The widget being used to draw into is the DrawArea widget. This is a composite widget which can also be used for graphics. The Window-id of a widget is obtained by using the XtWindow function.
The third parameter is the Graphics Context. This is a data-structure which is used to store information about the current graphics setting. It stores current colours (foreground and background), line-style (dotted etc), line-width etc.
The lines program needs to find the default foreground and background so that the lines are drawn in the correct colours. This is done by reading the XtNforeground, XtNbackground resource values from the main widget. The values are copied into the XGCValues structure and used in the creation of the graphics context. If you wish to change the line-width or some other attribute then you would do this in a similar way.
Try adding: values.line_style = LineOnOffDash;
before the XtGetGC function, and change the value mask in the XtGetGC function to "GCForeground | GCBackground | GCLineStyle".
For more GC functions, see the xman page for XCreateGC.