X-Windows in Assembly Language: Part II - THE.UNIX.WORLD
Pubblicato da mammon_ il 03/1999
Livello intermedio
Introduzione
/* Questo articolo e' stato tratto dall'Assembly Programming Journal numero 3 */
::/ \::::::. :/___\:::::::. /| \::::::::. :| _/\:::::::::. :| _ |\ \::::::::::. :::\_____\:::::::::::............................................THE.UNIX.WORLD
Iniziamo
OK, let's face it: you've seen the tedium of XLib, one *has* to use widgets in order to get any programming done in XWindows. 'But this is assembly langauge', the masochist might point out. 'Aren't widgets a little Visual-Basicy?'
Not in the slightest. A widget is simply a C++ class exported for use --much like the windows API functions, only a little more object oriented...maybe a good comparison would be MFC or VCL. Xt, or 'X toolkit Intrinsics', is the interface that widget sets [such as Athena, Qt or GTK] use to interface with XLib. The Xt include files are in /usr/X11R6/include/X11, its libraries are in /usr/X11R6/lib, and its exported functions are all prefixed with "Xt".
For the following examples I will be using the Atehna widget set, which is supplied with XFree86. The include files for Athena are in /usr/X11R6/include/Xaw and the libraries are in /usr/X11R6/lib.
A barebones Xt/Athena app in C would run as follows:
//====================================================================-xthell.c
#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#include <X11/Xaw/Command.h>
void Quit(w, client_data, call_data) //CallBack function
Widget w;
XtPointer client_data, call_data;
{
exit(0);
}
main(argc,argv)
int argc;
char **argv;
{
XtAppContext app_context;
Widget ShellWidge, ButtnWidge;
ShellWidge = XtVaAppInitialize( &app_context, "toplevel", NULL, 0, &argc, argv, NULL, NULL);
ButtnWidge = XtVaCreateManagedWidget("hellbutton", commandWidgetClass, ShellWidge, NULL);
XtAddCallback(ButtnWidge, XtNcallback, Quit, 0);
XtRealizeWidget(ShellWidge);
XtAppMainLoop(app_context);
}
// compile with cc -o xthell xthello.c -lXmu -lXaw -lXt -lX11 -L/usr/X11R6/lib
//=========================================================================-EOF
Pretty ugly, eh? This boils down to the following steps:
;===================================================================-xthell.asm
BITS 32
GLOBAL main
GLOBAL bail
EXTERN XtVaAppInitialize
EXTERN XtVaCreateManagedWidget
EXTERN XtAddCallback
EXTERN XtRealizeWidget
EXTERN XtAppMainLoop
EXTERN commandWidgetClass
EXTERN exit
SECTION .data
AppContext DD 0
ShellWidge DD 0
ButtnWidge DD 0
ARGC times 128 DB 0
ClassName DB "toplevel",0
ButtnName DB "hellbutton",0
XtNcallback DB "callback",0 ;XtNcallback
SECTION .text
bail:
pop eax ; Xt_Pointer call_data
pop ebx ; Xt_Pointer client_data
pop ecx ; Xt_Pointer widget
push dword 0
call exit
;-------------------------- main
main:
mov eax, esp
push dword 0 ;Number of Args
push dword 0 ;Args
push dword 0 ;Fallback Resources
push dword 0 ;argv
push dword ARGC ;&argc
push dword 0 ;Number of Options
push dword 0 ;Options Array
push dword ClassName ;Class Name (String)
push dword AppContext ;Application Context (Ptr)
call XtVaAppInitialize
add esp, 36
mov [ShellWidge], eax
push dword 0
push eax ;Button parent (ShellWidge)
push dword [commandWidgetClass] ;Button widget type
push dword ButtnName ;Button class name
call XtVaCreateManagedWidget
add esp, 16
mov [ButtnWidge], eax
push dword 0 ; client_data
push dword bail ;CallBack function
push dword XtNcallback ; callback type
push eax ;CallBack widget (ButtonWidge)
call XtAddCallback
add esp, 16
push dword [ShellWidge] ;Widget Handle
call XtRealizeWidget
add esp, 4
push dword [AppContext]
call XtAppMainLoop
add esp, 4
ret
;==========================================================================-EOF
This can be compiled with the following commands:
nasm -f elf xthell.asm
gcc -o xthell xthell.o -lXaw -lXt -lX11 -L/usr/X11R6/lib
Most of the operation is the same as the C file; naturally you must push dword 0's instead of NULLs...and do not forget to push the arguments in reverse order and to clean up the stack afterwards; this is C after all and not stdcall is used in Windows.
;=======================================================================-xt.mac
%macro CLASS 2
%1: DB %2,0
%endmacro
%macro WDGTPTR 1
%1: DD 0
%endmacro
%macro CONTEXT 1
%1: DD 0
%endmacro
%macro CHARSTR 2
%1: DB %2,0
%endmacro
%define WIDGET EXTERN
%define XLibAPI EXTERN
%define XtAPI EXTERN
%define PUBLIC GLOBAL
%define NULL dword 0
%define TERM_VARARGS dword 0
%macro InitXt 2
SECTION .data
CONTEXT AppContext
CLASS XtShell, "XtShell"
SECTION .text
EXTERN XtVaAppInitialize
push dword 0 ;Number of Args
push dword 0 ;Args
push dword 0 ;Fallback Resources
push dword 0 ;argv
push dword %2 ;&argc
push dword 0 ;Number of Options
push dword 0 ;Options Array
push dword XtShell ;Class Name (String)
push dword AppContext ;Application Context (Ptr)
call XtVaAppInitialize
add esp, 36
mov [%1], eax
%endmacro
%macro XtMsgLoop 0
EXTERN XtAppMainLoop
push dword [AppContext]
call XtAppMainLoop
add esp, 4
%endmacro
%macro RegisterCallback 1
SECTION .data
CBType: DB "callback",0
SECTION .code
push NULL
push dword %1 ;CallBack function
push dword CBType
push eax ;CallBack parent (ButtonWidge)
call XtAddCallback
add esp, 16
%endmacro
%macro CALLBACK 1
SECTION .data
Call_Data_%1: DD 0
Client_Data_%1: DD 0
Widget_%1: DD 0
GLOBAL %1
SECTION .text
%1:
pop eax
mov [Call_Data_%1], eax
pop ebx
mov [Client_Data_%1], ebx
pop ecx
mov [Widget_%1], ecx
%endmacro
%define ENDCALLBACK nop
%macro ENTRYPOINT 1
GLOBAL %1
%1:
%endmacro
;==========================================================================-EOF
Most of the macro file should be readily apparent if you are familiar with the NASM macro facility. I did take the opportunity to clean up the callback function, so that the parameters to the callback are saved in variables, but for the most part it does the same as the equivalent code in the preceding asm example.
;===================================================================-xthell.asm
BITS 32
%INCLUDE "xt.mac"
;========================================================XTRN=====
XtAPI XtVaCreateManagedWidget
XtAPI XtAddCallback
XtAPI XtRealizeWidget
WIDGET commandWidgetClass
EXTERN exit
;========================================================DATA=====
SECTION .data
;------------
WDGTPTR ptrShell
WDGTPTR ptrButton
CLASS XHELL, "XHell"
CLASS HellButton, "HellButton"
CallbackType DB "callback",0 ;XtNcallback
ARGC times 128 DB 0
;========================================================CODE=====
SECTION .text
;------------
CALLBACK bail
push dword 0
call exit
ENDCALLBACK
ENTRYPOINT main
InitXt ptrShell, ARGC
push TERM_VARARGS
push eax ;Button parent (ShellWidge)
push dword [commandWidgetClass] ;Button widget type
push dword HellButton ;Button class name
call XtVaCreateManagedWidget
add esp, 16
mov [ptrButton], eax
RegisterCallback bail
push dword [ptrShell] ;Widget Handle
call XtRealizeWidget
add esp, 4
XtMsgLoop
ret
;==========================================================================-EOF
Much prettier and hey, only twice as long as the C version! ;)
Conclusioni
Next issue I will dwell on Xt/Athena a little longer and come up with some more practical methods of automating the coding process.