Window creation/X11: Difference between revisions

→‎{{header|Tcl}}: Rewrite to be clearer about how different levels of interface can exist
(→‎{{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 package===
{{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 Tcl 8.5xlib
 
package provide x 11
XOpenDisplay {}
renameset ::w [XCreateSimpleWindow ::x::Window 10 10 100 100 1]
XMapWindow $w
while {[XNextEvent] == "expose"} {
XFillRectangle $w 20 20 10 10
XDrawString $w 10 50 "Hello, World!"
}
XDestroyWindow $w
XCloseDisplay</lang>
===HighHigher level interface package===
Just because there is a low level package does not mean that it is pleasant to use from Tcl code. Therefore itthis issecond wrappedpackage wraps it up inside a higher-level package that provides a more natural way of interacting.
<lang tcl>package require xlibTcl 8.6
package provide xx11 111
 
namespace eval ::x {
Line 277 ⟶ 294:
 
proc display {script} {
OpenDisplayXOpenDisplay {}
catch {uplevel 1 $script} msg opts
XCloseDisplay
CloseDisplay
return -options $opts $msg
}
Line 285 ⟶ 302:
upvar 1 $var v
while 1 {
set v [WaitForEventXNextEvent]
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
variable maskw
rename ::XOpenDisplay ::x::OpenDisplay
proc window constructor {x y width height events} {
rename ::XCloseDisplay ::x::CloseDisplay
set m 0
rename ::XCreateSimpleWindow ::x::Window
variable ::x::mask
rename ::XMapWindow ::x::map
foreach e $events {catch {incr m $mask($e)}}
rename ::XUnmapWindow ::x::unmap
set w [XCreateSimpleWindow $x $y $width $height $m]
rename ::XNextEvent ::x::WaitForEvent
}
rename ::XFillRectangle ::x::fillrect
method map {} {
rename ::XDrawString ::x::text</lang>
XMapWindow $w
===Demonstration script===
}
method unmap {} {
XUnmapWindow $w
}
Windowmethod $fill {x $y $width $height} $m{
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>lappendpackage auto_pathrequire lib .x11
package require x
 
# With a display connection open, create and map a window
x display {
set w [x window new 10 10 100 100 KeyPress]
x$w map $w
 
x eventloop e {
expose {
# Paint the window
x fillrect $w fill 20 20 10 10
x$w text $w 10 50 "Hello, World!"
}
key {
Line 327 ⟶ 351:
}
}
 
$w destroy
}</lang>
Improving this by adding more sophisticated event handling and more window methods is left as an exercise.
Anonymous user