Anonymous user
Window creation/X11: Difference between revisions
→{{header|Tcl}}: Rewrite to be clearer about how different levels of interface can exist
(→Demonstration script: Add comments) |
(→{{header|Tcl}}: Rewrite to be clearer about how different levels of interface can exist) |
||
Line 196:
Tcl does not come with a low-level connection to the X protocol, as it has long been distributed with [[Tk]] which offers a much higher-level interface (and which is portable to other platforms too). This means that the interface has to be crafted directly. This can be done with either [http://www.swig.org/ SWIG] or [[critcl]]. This example shows how to do it the latter way:
===Low level interface
{{libheader|critcl}}
<lang tcl>package provide xlib 1
Line 204:
critcl::ccode {
#include <X11/Xlib.h>
static Display *d;
static GC gc;
}
# Display connection functions
critcl::cproc XOpenDisplay {Tcl_Interp* interp char* name} ok {
d = XOpenDisplay(name[0] ? name : NULL);
Line 217 ⟶ 218:
return TCL_OK;
}
critcl::cproc XCloseDisplay {} void {
XCloseDisplay(d);
}
# Basic window functions
critcl::cproc XCreateSimpleWindow {
int x int y int width int height int events
Line 231 ⟶ 232:
return (int) w;
}
critcl::cproc XDestroyWindow {int w} void {
XDestroyWindow(d, (Window) w);
}▼
critcl::cproc XMapWindow {int w} void {
XMapWindow(d, (Window) w);
Line 239 ⟶ 242:
}
# Event receiver
critcl::cproc XNextEvent {Tcl_Interp* interp} char* {
XEvent e;
Line 250 ⟶ 254:
}
# Painting functions
critcl::cproc XFillRectangle {int w int x int y int width int height} void {
XFillRectangle(d, (Window)w, gc, x, y, width, height);
}
critcl::cproc XDrawString {int w int x int y Tcl_Obj* msg} void {
int len;
Line 260 ⟶ 264:
}</lang>
Note that this only does enough for this demo. A full adaptation is too long for RosettaCode...
===High level interface package===▼
This could then be used like this:
Just because there is a low level package does not mean that it is pleasant to use from Tcl code. Therefore it is wrapped up inside a higher-level package that provides a more natural way of interacting.▼
<lang tcl>package require
package provide x 11▼
XOpenDisplay {}
XMapWindow $w
while {[XNextEvent] == "expose"} {
XFillRectangle $w 20 20 10 10
XDrawString $w 10 50 "Hello, World!"
}
XDestroyWindow $w
XCloseDisplay</lang>
▲Just because there is a low level package does not mean that it is pleasant to use from Tcl code. Therefore
namespace eval ::x {
Line 277 ⟶ 294:
proc display {script} {
catch {uplevel 1 $script} msg opts
XCloseDisplay
return -options $opts $msg
}
Line 285 ⟶ 302:
upvar 1 $var v
while 1 {
set v [
uplevel 1 [list switch $v $handlers]
}
}
proc window {x y width height events} {▼
set m 0▼
variable mask▼
foreach e $events {catch {incr m $mask($e)}}▼
Window $x $y $width $height $m▼
}▼
▲}
oo::class create window {
▲package require xlib
▲rename ::XCreateSimpleWindow ::x::Window
variable ::x::mask
set w [XCreateSimpleWindow $x $y $width $height $m]
}
method map {} {
XMapWindow $w
}
method unmap {} {
XUnmapWindow $w
}
XFillRectangle $w $x $y $width $height
}
method text {x y string} {
XDrawString $w $x $y $string
}
destructor {
XDestroyWindow $w
}
▲ }
}</lang>
This script puts the pieces together to carry out the details of the task.
<lang tcl>
# With a display connection open, create and map a window
x display {
set w [x window new 10 10 100 100 KeyPress]
x eventloop e {
expose {
# Paint the window
}
key {
Line 327 ⟶ 351:
}
}
$w destroy
}</lang>
Improving this by adding more sophisticated event handling and more window methods is left as an exercise.
|