Unix.XDisplay.Mod 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864
  1. (* ETH Oberon, Copyright 2000 ETH Zürich Institut für Computersysteme, ETH Zentrum, CH-8092 Zürich.
  2. Refer to the general ETH Oberon System license contract available at: http://www.oberon.ethz.ch/ *)
  3. MODULE XDisplay; (** AUTHOR "gf"; PURPOSE "display driver plugin for X Windows *)
  4. IMPORT S := SYSTEM, Trace, Unix, Machine, Files, UnixFiles, X11, Api := X11Api, Displays, Strings;
  5. CONST
  6. BG = 0; FG = 15; (* Background, foreground colors.*)
  7. CONST
  8. (* formats for Transfer. value DIV 8 = bytes per pixel. *)
  9. unknown = 0;
  10. index8 = 8; color555 = 16; color565 = 17; color664 = 18;
  11. color888 = 24; color8888* = 32;
  12. (* Drawing operation modes. *)
  13. replace = 0; (* destcolor := sourcecolor. *)
  14. paint = 1; (* destcolor := destcolor OR sourcecolor. *)
  15. invert = 2; (* destcolor := destcolor XOR sourcecolor. *)
  16. VAR
  17. winName, iconName: ARRAY 128 OF CHAR;
  18. TYPE
  19. RGB = RECORD
  20. r, g, b: INTEGER
  21. END;
  22. Clip* = OBJECT
  23. VAR
  24. d: Display; lx, ly, lw, lh: LONGINT;
  25. PROCEDURE & Init( disp: Display );
  26. BEGIN
  27. d := disp; lx := 0; ly := 0; lw := 0; lh := 0;
  28. Reset
  29. END Init;
  30. PROCEDURE Set*( x, y, w, h: LONGINT );
  31. VAR rect: X11.Rectangle;
  32. BEGIN
  33. IF w < 0 THEN w := 0 END;
  34. IF h < 0 THEN h := 0 END;
  35. IF (x # lx) OR (y # ly) OR (w # lw) OR (h # lh) THEN
  36. lx := x; ly := y; lw := w; lh := h;
  37. IF y < d.height THEN d.currwin := d.primary ELSE d.currwin := d.secondary; DEC( y, d.height ) END;
  38. rect.x := SHORT( x ); rect.y := SHORT( y );
  39. rect.w := SHORT( w ); rect.h := SHORT( h );
  40. Machine.Acquire( Machine.X11 );
  41. IF (rect.x <= 0) & (rect.y <= 0) & (rect.w >= d.width) & (rect.h >= d.height) THEN
  42. X11.SetClipMask( d.xdisp, d.gc, X11.None ) (* no clipping *)
  43. ELSE
  44. X11.SetClipRectangles( d.xdisp, d.gc, 0, 0, ADDRESSOF( rect ), 1, X11.YXBanded )
  45. END;
  46. Machine.Release( Machine.X11 )
  47. END;
  48. END Set;
  49. PROCEDURE Get*( VAR x, y, w, h: LONGINT );
  50. BEGIN
  51. x := lx; y := ly; w := lw; h := lh
  52. END Get;
  53. PROCEDURE InClip*( x, y, w, h: LONGINT ): BOOLEAN;
  54. BEGIN
  55. RETURN (x >= lx) & (x + w <= lx + lw) & (y >= ly) & (y + h <= ly + lh)
  56. END InClip;
  57. PROCEDURE Reset*;
  58. BEGIN
  59. Set( 0, 0, d.width, d.height );
  60. END Reset;
  61. (** Intersect with current clip rectangle resulting in a new clip rectangle. *)
  62. PROCEDURE Adjust*( x, y, w, h: LONGINT ); (* intersection *)
  63. VAR x0, y0, x1, y1: LONGINT;
  64. BEGIN
  65. IF x > lx THEN x0 := x ELSE x0 := lx END;
  66. IF y > ly THEN y0 := y ELSE y0 := ly END;
  67. IF x + w < lx + lw THEN x1 := x + w ELSE x1 := lx + lw END;
  68. IF y + h < ly + lh THEN y1 := y + h ELSE y1 := ly + lh END;
  69. Set( x0, y0, x1 - x0, y1 - y0 );
  70. END Adjust;
  71. END Clip;
  72. Display* = OBJECT (Displays.Display)
  73. VAR
  74. xdisp- : X11.DisplayPtr;
  75. primary- : X11.Window;
  76. secondary- : X11.Window;
  77. currwin : X11.Window;
  78. wmDelete- : X11.Atom;
  79. screen : LONGINT;
  80. visual{UNTRACED} : X11.VisualPtr;
  81. depth : LONGINT;
  82. bigEndian : BOOLEAN;
  83. gc : X11.GC;
  84. clip : Clip;
  85. cmap : X11.Colormap;
  86. planesMask : LONGINT;
  87. foreground,
  88. background : LONGINT;
  89. rgb, defPal : ARRAY 256 OF RGB; (* 8-bit pseudo color *)
  90. pixel : ARRAY 256 OF LONGINT; (* pixel values for Oberon colors *)
  91. xformat : LONGINT;
  92. currcol, currmode : LONGINT;
  93. xfunc : ARRAY 3 OF LONGINT;
  94. PROCEDURE SetMode( col: LONGINT );
  95. VAR mode: LONGINT;
  96. BEGIN
  97. mode := replace;
  98. IF (col # -1) & (30 IN S.VAL( SET, col )) THEN mode := invert; EXCL( S.VAL( SET, col ), 30 ) END;
  99. IF mode # currmode THEN X11.SetFunction( xdisp, gc, xfunc[mode] ); currmode := mode END;
  100. IF col # currcol THEN X11.SetForeground( xdisp, gc, ColorToPixel( col ) ); currcol := col END;
  101. END SetMode;
  102. PROCEDURE Dot*( col, x, y: LONGINT );
  103. BEGIN
  104. IF currwin = secondary THEN DEC( y, height ) END;
  105. Machine.Acquire( Machine.X11 );
  106. SetMode( col );
  107. X11.DrawPoint( xdisp, currwin, gc, x, y );
  108. Machine.Release( Machine.X11 )
  109. END Dot;
  110. PROCEDURE Fill*( col, x, y, w, h: LONGINT );
  111. BEGIN
  112. IF (h > 0) & (w > 0) THEN
  113. IF currwin = secondary THEN DEC( y, height ) END;
  114. Machine.Acquire( Machine.X11 );
  115. SetMode( col );
  116. X11.FillRectangle( xdisp, currwin, gc, x, y, w, h );
  117. Machine.Release( Machine.X11 )
  118. END
  119. END Fill;
  120. (** Transfer a block of pixels in "raw" display format to (op = set) or from (op = get) the display.
  121. Pixels in the rectangular area are transferred from left to right and top to bottom. The pixels
  122. are transferred to or from "buf", starting at "ofs". The line byte increment is "stride", which may
  123. be positive, negative or zero. *)
  124. PROCEDURE Transfer*( VAR buf: ARRAY OF CHAR; ofs, stride, x, y, w, h, op: LONGINT );
  125. CONST Get = 0; Set = 1;
  126. VAR image: X11.Image;
  127. imp: X11.ImagePtr;
  128. bp, ip: ADDRESS;
  129. line, ll: LONGINT;
  130. BEGIN
  131. ll := w*(xformat DIV 8);
  132. IF (ofs + (h - 1)*stride + ll > LEN( buf )) OR (ofs + (h - 1)*stride < 0) THEN HALT( 99 ) END;
  133. IF LEN( imgBuffer ) < 4*w*h THEN
  134. NEW( imgBuffer, 4*w*h ); (* create buffer outside lock to avoid deadlock *)
  135. END;
  136. bp := ADDRESSOF( buf[ofs] );
  137. IF op = Set THEN
  138. Machine.Acquire( Machine.X11 );
  139. image := X11.CreateImage( xdisp, visual, depth, X11.ZPixmap, 0, 0, w, h, 32, 0 );
  140. imp := S.VAL( X11.ImagePtr, image );
  141. imp.data := ADDRESSOF( imgBuffer[0] ); ip := imp.data;
  142. IF imp.byteOrder = 0 THEN
  143. FOR line := 0 TO h - 1 DO
  144. PutLine( xformat, w, ip, bp );
  145. INC( bp, stride ); INC( ip, imp.bytesPerLine )
  146. END;
  147. ELSE
  148. FOR line := 0 TO h - 1 DO
  149. PutLineBE( xformat, w, ip, bp );
  150. INC( bp, stride ); INC( ip, imp.bytesPerLine )
  151. END;
  152. END;
  153. IF currmode # replace THEN
  154. X11.SetFunction( xdisp, gc, xfunc[replace] ); currmode := replace
  155. END;
  156. X11.PutImage( xdisp, primary, gc, image, 0, 0, x, y, w, h );
  157. X11.Free( image ); imp := NIL;
  158. Machine.Release( Machine.X11 )
  159. ELSIF op = Get THEN
  160. Machine.Acquire( Machine.X11 );
  161. image := X11.GetImage( xdisp, primary, x, y, w, h, planesMask, X11.ZPixmap );
  162. imp := S.VAL( X11.ImagePtr, image ); ip := imp.data;
  163. IF imp.byteOrder = 0 THEN
  164. FOR line := 0 TO h - 1 DO
  165. GetLine( xformat, w, ip, bp );
  166. INC( bp, stride ); INC( ip, imp.bytesPerLine )
  167. END
  168. ELSE
  169. FOR line := 0 TO h - 1 DO
  170. GetLineBE( xformat, w, ip, bp );
  171. INC( bp, stride ); INC( ip, imp.bytesPerLine )
  172. END
  173. END;
  174. X11.Free( imp.data ); X11.Free( image ); imp := NIL;
  175. Machine.Release( Machine.X11 )
  176. END;
  177. END Transfer;
  178. (** Transfer a block of pixels from a 1-bit mask to the display. Pixels in the rectangular area are
  179. transferred from left to right and top to bottom. The pixels are transferred from "buf", starting
  180. at bit offset "bitofs". The line byte increment is "stride", which may be positive, negative or zero.
  181. "fg" and "bg" specify the colors for value 1 and 0 pixels respectively. *)
  182. PROCEDURE Mask*( VAR buf: ARRAY OF CHAR; bitofs, stride, fg, bg, x, y, w, h: LONGINT );
  183. VAR p: ADDRESS; i: LONGINT; s: SET;
  184. image: X11.Image;
  185. fgpixel, bgpixel, xret: LONGINT;
  186. ix, iy, ih: LONGINT;
  187. imp: X11.ImagePtr;
  188. BEGIN
  189. IF (w > 0) & (h > 0) THEN
  190. IF fg >= 0 THEN fgpixel := pixel[fg MOD 256] ELSE fgpixel := ColorToPixel( fg ) END;
  191. IF bg >= 0 THEN bgpixel := pixel[bg MOD 256] ELSE bgpixel := ColorToPixel( bg ) END;
  192. IF LEN( imgBuffer ) < 4*w*h THEN
  193. NEW( imgBuffer, 4*w*h ); (* create buffer outside lock to avoid deadlock *)
  194. END;
  195. Machine.Acquire( Machine.X11 );
  196. image := X11.CreateImage( xdisp, visual, depth, X11.ZPixmap, 0, 0, w, h, 32, 0 );
  197. imp := S.VAL( X11.ImagePtr, image );
  198. imp.data := ADDRESSOF( imgBuffer[0] );
  199. i := LONGINT(ADDRESSOF( buf[0] ) MOD 4); INC( bitofs, i*8 );
  200. p := ADDRESSOF( buf[0] ) - i + bitofs DIV 32*4; (* p always aligned to 32-bit boundary *)
  201. bitofs := bitofs MOD 32; stride := stride*8;
  202. ix := 0; iy := 0; ih := h;
  203. LOOP
  204. S.GET( p, s ); i := bitofs;
  205. LOOP
  206. IF (i MOD 32) IN s THEN xret := X11.PutPixel( image, ix, iy, fgpixel );
  207. ELSE xret := X11.PutPixel( image, ix, iy, bgpixel );
  208. END;
  209. INC( i ); INC( ix );
  210. IF i - bitofs = w THEN EXIT END;
  211. IF i MOD 32 = 0 THEN S.GET( p + i DIV 8, s ) END
  212. END;
  213. DEC( ih );
  214. IF ih = 0 THEN EXIT END;
  215. INC( iy ); ix := 0; INC( bitofs, stride );
  216. IF (bitofs >= 32) OR (bitofs < 0) THEN (* moved outside s *)
  217. INC( p, bitofs DIV 32*4 ); bitofs := bitofs MOD 32
  218. END
  219. END; (* loop *)
  220. IF currmode # replace THEN X11.SetFunction( xdisp, gc, xfunc[replace] ) END;
  221. X11.PutImage( xdisp, primary, gc, image, 0, 0, x, y, w, h );
  222. IF currmode # replace THEN X11.SetFunction( xdisp, gc, xfunc[currmode] ) END;
  223. X11.Free( image );
  224. Machine.Release( Machine.X11 );
  225. END
  226. END Mask;
  227. (** Copy source block sx, sy, w, h to destination dx, dy. Overlap is allowed. *)
  228. PROCEDURE Copy*( sx, sy, w, h, dx, dy: LONGINT );
  229. VAR src: X11.DisplayPtr;
  230. BEGIN
  231. IF (w > 0) & (h > 0) THEN
  232. IF sy < height THEN src := primary ELSE src := secondary; DEC( sy, height ) END;
  233. IF currwin = secondary THEN DEC( sy, height ) END;
  234. Machine.Acquire( Machine.X11 );
  235. SetMode( currcol );
  236. X11.CopyArea( xdisp, src, currwin, gc, sx, sy, w, h, dx, dy );
  237. Machine.Release( Machine.X11 )
  238. END;
  239. END Copy;
  240. (** Update the visible display (if caching is used). *)
  241. PROCEDURE Update*;
  242. BEGIN
  243. Machine.Acquire( Machine.X11 );
  244. X11.Sync( xdisp, X11.False );
  245. Machine.Release( Machine.X11 )
  246. END Update;
  247. (** Map a color value to an 8-bit CLUT index. Only used if xformat = index8. *)
  248. PROCEDURE ColorToIndex*( col: LONGINT ): LONGINT;
  249. BEGIN
  250. RETURN ColorToIndex0( SELF, col )
  251. END ColorToIndex;
  252. (** Map an 8-bit CLUT index to a color value. Only used if xformat = index8. *)
  253. PROCEDURE IndexToColor*( n: LONGINT ): LONGINT;
  254. VAR r, g, b: LONGINT;
  255. BEGIN
  256. IF n >= 0 THEN
  257. IF n > 255 THEN n := BG END;
  258. r := rgb[n].r; g := rgb[n].g; b := rgb[n].b;
  259. RETURN MIN( LONGINT ) + (r*100H + g)*100H + b
  260. ELSE RETURN n
  261. END;
  262. END IndexToColor;
  263. PROCEDURE SetColor*( col, red, green, blue: INTEGER ); (* 0 <= col, red, green, blue < 256 *)
  264. VAR xcol: X11.Color; res: LONGINT;
  265. BEGIN
  266. IF (col < 0) OR (col > 255) THEN RETURN END;
  267. rgb[col].r := red; rgb[col].g := green; rgb[col].b := blue;
  268. xcol.red := 256*red; xcol.green := 256*green; xcol.blue := 256*blue;
  269. Machine.Acquire( Machine.X11 );
  270. IF depth > 8 THEN
  271. res := X11.AllocColor( xdisp, cmap, ADDRESSOF( xcol ) );
  272. IF res # 0 THEN pixel[col] := xcol.pixel END
  273. ELSE
  274. xcol.flags := CHR( X11.DoAll ); xcol.pixel := pixel[col];
  275. X11.StoreColor( xdisp, cmap, ADDRESSOF( xcol ) )
  276. END;
  277. Machine.Release( Machine.X11 )
  278. END SetColor;
  279. PROCEDURE GetColor*( col: INTEGER; VAR red, green, blue: INTEGER );
  280. BEGIN
  281. IF (0 <= col) & (col <= 255) THEN
  282. red := rgb[col].r; green := rgb[col].g; blue := rgb[col].b
  283. ELSE
  284. red := rgb[BG].r; green := rgb[BG].g; blue := rgb[BG].b
  285. END
  286. END GetColor;
  287. PROCEDURE ColorToPixel*( col: LONGINT ): LONGINT;
  288. VAR r, g, b, i, ii, x, y, z, m, min: LONGINT; rc: RGB;
  289. BEGIN
  290. r := LSH( col, -16 ) MOD 256; g := LSH( col, -8 ) MOD 256; b := col MOD 256;
  291. CASE xformat OF
  292. color8888, color888:
  293. IF bigEndian THEN RETURN ASH( b, 16 ) + ASH( g, 8 ) + r
  294. ELSE RETURN ASH( r, 16 ) + ASH( g, 8 ) + b
  295. END
  296. | color555:
  297. r := 32*r DIV 256; g := 32*g DIV 256; b := 32*b DIV 256;
  298. IF bigEndian THEN RETURN ASH( b, 10 ) + ASH( g, 5 ) + r
  299. ELSE RETURN ASH( r, 10 ) + ASH( g, 5 ) + b
  300. END
  301. | color565:
  302. r := 32*r DIV 256; g := 64*g DIV 256; b := 32*b DIV 256;
  303. IF bigEndian THEN RETURN ASH( b, 11 ) + ASH( g, 5 ) + r
  304. ELSE RETURN ASH( r, 11 ) + ASH( g, 5 ) + b
  305. END
  306. | color664:
  307. r := 64*r DIV 256; g := 64*g DIV 256; b := 16*b DIV 256;
  308. IF bigEndian THEN RETURN ASH( b, 12 ) + ASH( g, 6 ) + r
  309. ELSE RETURN ASH( r, 10 ) + ASH( g, 4 ) + b
  310. END
  311. ELSE (* index8 *)
  312. i := 0; ii := 0; min := MAX( LONGINT );
  313. WHILE (i < 256) & (min > 0) DO
  314. rc := rgb[i];
  315. x := ABS( r - rc.r ); y := ABS( g - rc.g ); z := ABS( b - rc.b ); m := x;
  316. IF y > m THEN m := y END;
  317. IF z > m THEN m := z END;
  318. m := m*m + (x*x + y*y + z*z);
  319. IF m < min THEN min := m; ii := i END;
  320. INC( i )
  321. END;
  322. RETURN pixel[ii]
  323. END
  324. END ColorToPixel;
  325. PROCEDURE & Initialize( disp: X11.DisplayPtr; absWidth, absHeight, relWidth, relHeight: LONGINT );
  326. VAR
  327. event: Api.XEvent; root: X11.Window;
  328. gRoot, gX, gY, gW, gH, gBW, gD, res: LONGINT; screenw, screenh : LONGINT;
  329. BEGIN
  330. xdisp := disp;
  331. screen := X11.DefaultScreen( xdisp );
  332. screenw := X11.DisplayWidth( xdisp, screen );
  333. screenh := X11.DisplayHeight( xdisp, screen );
  334. depth := X11.DefaultDepth( xdisp, screen );
  335. cmap := X11.DefaultColormap( xdisp, screen );
  336. foreground := X11.BlackPixel( xdisp, screen );
  337. background := X11.WhitePixel( xdisp, screen );
  338. Machine.Acquire( Machine.X11 );
  339. root := X11.DefaultRootWindow( xdisp );
  340. primary := X11.CreateSimpleWindow( xdisp, root, 0, 0,
  341. screenw - 16, screenh - 32, 0,
  342. foreground, background );
  343. X11.StoreName( xdisp, primary, ADDRESSOF( winName ) );
  344. X11.SetIconName( xdisp, primary, ADDRESSOF( iconName ) );
  345. X11.SetCommand( xdisp, primary, Unix.argv, Unix.argc );
  346. X11.SelectInput( xdisp, primary, X11.ExposureMask );
  347. (* set wm_delete_events if in windowed mode *)
  348. wmDelete := Api.InternAtom(xdisp, "WM_DELETE_WINDOW", Api.True);
  349. res := Api.SetWMProtocols(xdisp, primary, ADDRESSOF(wmDelete), 1);
  350. X11.MapRaised( xdisp, primary );
  351. REPEAT Api.NextEvent( xdisp, event )
  352. UNTIL (event.typ = Api.Expose) & (event.window = primary);
  353. (* adjust to physical window size *)
  354. X11.GetGeometry( xdisp, primary, gRoot, gX, gY, gW, gH, gBW, gD );
  355. IF relWidth # -1 THEN
  356. gW := relWidth * gW DIV 100;
  357. ELSE
  358. gW := absWidth;
  359. END;
  360. IF relHeight # -1 THEN
  361. gH := relHeight * gH DIV 100;
  362. ELSE
  363. gH := absHeight;
  364. END;
  365. IF gW MOD 8 # 0 THEN DEC( gW, gW MOD 8 ) END;
  366. X11.ResizeWindow( xdisp, primary, gW, gH );
  367. width := gW; height := gH;
  368. offscreen := height;
  369. (* pixmap may not be larger than screen: *)
  370. IF gW > screenw THEN gW := screenw END;
  371. IF gH > screenh THEN gH := screenh END;
  372. secondary := X11.CreatePixmap( xdisp, primary, gW, gH, depth );
  373. Machine.Release( Machine.X11 );
  374. CreateColors( SELF ); InitPalette( SELF ); SuppressX11Cursors( SELF );
  375. InitFormat( SELF ); CreateGC( SELF ); InitFunctions( SELF );
  376. NEW( clip, SELF )
  377. END Initialize;
  378. (** Finalize the display. Further calls to display methods are not allowed, and may cause exceptions. *)
  379. PROCEDURE Finalize*;
  380. (*
  381. BEGIN (* should really be exclusive with Transfer, but we assume the caller keeps to the rules above *)
  382. fbadr := 0; fbsize := 0
  383. *)
  384. END Finalize;
  385. END Display;
  386. VAR
  387. dispname: ARRAY 128 OF CHAR;
  388. imgBuffer: POINTER TO ARRAY OF CHAR;
  389. PROCEDURE ColorToIndex0( disp: Display; col: LONGINT ): INTEGER;
  390. VAR idx, i: INTEGER; r, g, b, min, x, y, z, d: LONGINT; rc: RGB;
  391. BEGIN
  392. r := ASH( col, -16 ) MOD 100H; g := ASH( col, -8 ) MOD 100H; b := col MOD 100H;
  393. i := 0; idx := 0; min := MAX( LONGINT );
  394. WHILE (i < 256) & (min > 0) DO
  395. rc := disp.defPal[i]; x := ABS( r - rc.r ); y := ABS( g - rc.g ); z := ABS( b - rc.b ); d := x;
  396. IF y > d THEN d := y END;
  397. IF z > d THEN d := z END;
  398. d := d*d + (x*x + y*y + z*z);
  399. IF d < min THEN min := d; idx := i END;
  400. INC( i )
  401. END;
  402. RETURN idx
  403. END ColorToIndex0;
  404. PROCEDURE PutLine( xformat, width: LONGINT; ip, bp: ADDRESS );
  405. VAR i: LONGINT; byte: CHAR;
  406. BEGIN
  407. CASE xformat OF
  408. | index8:
  409. FOR i := 1 TO width DO
  410. S.GET( bp, byte ); S.PUT( ip, byte ); INC( bp ); INC( ip )
  411. END;
  412. | color565, color555, color664:
  413. FOR i := 1 TO width DO
  414. S.GET( bp, byte ); S.PUT( ip, byte ); INC( bp ); INC( ip );
  415. S.GET( bp, byte ); S.PUT( ip, byte ); INC( bp ); INC( ip )
  416. END;
  417. | color888:
  418. FOR i := 1 TO width DO
  419. S.GET( bp, byte ); S.PUT( ip, byte ); INC( bp ); INC( ip ); (* B *)
  420. S.GET( bp, byte ); S.PUT( ip, byte ); INC( bp ); INC( ip ); (* G *)
  421. S.GET( bp, byte ); S.PUT( ip, byte ); INC( bp ); INC( ip ); (* R *)
  422. byte := 0X; S.PUT( ip, byte ); INC( ip )
  423. END;
  424. ELSE (* color8888 *)
  425. FOR i := 1 TO width DO
  426. S.GET( bp, byte ); S.PUT( ip, byte ); INC( bp ); INC( ip ); (* B *)
  427. S.GET( bp, byte ); S.PUT( ip, byte ); INC( bp ); INC( ip ); (* G *)
  428. S.GET( bp, byte ); S.PUT( ip, byte ); INC( bp ); INC( ip ); (* R *)
  429. S.GET( bp, byte ); S.PUT( ip, byte ); INC( bp ); INC( ip ); (* X *)
  430. END
  431. END
  432. END PutLine;
  433. PROCEDURE GetLine( xformat, width: LONGINT; ip, bp: ADDRESS );
  434. VAR i: LONGINT; byte: CHAR;
  435. BEGIN
  436. CASE xformat OF
  437. | index8:
  438. FOR i := 1 TO width DO
  439. S.GET( ip, byte ); S.PUT( bp, byte ); INC( ip ); INC( bp )
  440. END;
  441. | color565, color555, color664:
  442. FOR i := 1 TO width DO
  443. S.GET( ip, byte ); S.PUT( bp, byte ); INC( ip ); INC( bp );
  444. S.GET( ip, byte ); S.PUT( bp, byte ); INC( ip ); INC( bp )
  445. END
  446. | color888:
  447. FOR i := 1 TO width DO
  448. S.GET( ip, byte ); S.PUT( bp, byte ); INC( ip ); INC( bp ); (* B *)
  449. S.GET( ip, byte ); S.PUT( bp, byte ); INC( ip ); INC( bp ); (* G *)
  450. S.GET( ip, byte ); S.PUT( bp, byte ); INC( ip ); INC( bp ); (* R *)
  451. INC( ip )
  452. END
  453. ELSE (* color8888 *)
  454. FOR i := 1 TO width DO
  455. S.GET( ip, byte ); S.PUT( bp, byte ); INC( ip ); INC( bp ); (* B *)
  456. S.GET( ip, byte ); S.PUT( bp, byte ); INC( ip ); INC( bp ); (* G *)
  457. S.GET( ip, byte ); S.PUT( bp, byte ); INC( ip ); INC( bp ); (* R *)
  458. S.GET( ip, byte ); S.PUT( bp, byte ); INC( ip ); INC( bp ); (* X *)
  459. END
  460. END;
  461. END GetLine;
  462. PROCEDURE PutLineBE( xformat, width: LONGINT; ip, bp: ADDRESS );
  463. VAR i: LONGINT; byte: CHAR;
  464. BEGIN
  465. CASE xformat OF
  466. index8:
  467. FOR i := 1 TO width DO
  468. S.GET( bp, byte ); S.PUT( ip, byte ); INC( bp ); INC( ip )
  469. END
  470. | color565, color555, color664:
  471. FOR i := 1 TO width DO
  472. S.GET( bp + 1, byte ); S.PUT( ip, byte ); INC( ip );
  473. S.GET( bp + 0, byte ); S.PUT( ip, byte ); INC( ip );
  474. INC( bp, 2 )
  475. END
  476. | color888:
  477. FOR i := 1 TO width DO
  478. byte := 0X; S.PUT( ip, byte ); INC( ip );
  479. S.GET( bp + 2, byte ); S.PUT( ip, byte ); INC( ip ); (* B *)
  480. S.GET( bp + 1, byte ); S.PUT( ip, byte ); INC( ip ); (* G *)
  481. S.GET( bp + 0, byte ); S.PUT( ip, byte ); INC( ip ); (* R *)
  482. INC( bp, 3 )
  483. END
  484. ELSE (* color8888 *)
  485. FOR i := 1 TO width DO
  486. S.GET( bp + 3, byte ); S.PUT( ip, byte ); INC( ip ); (* X *)
  487. S.GET( bp + 2, byte ); S.PUT( ip, byte ); INC( ip ); (* B *)
  488. S.GET( bp + 1, byte ); S.PUT( ip, byte ); INC( ip ); (* G *)
  489. S.GET( bp + 0, byte ); S.PUT( ip, byte ); INC( ip ); (* R *)
  490. INC( bp, 4 );
  491. END;
  492. END;
  493. END PutLineBE;
  494. PROCEDURE GetLineBE( xformat, width: LONGINT; ip, bp: ADDRESS );
  495. VAR i: LONGINT; byte: CHAR;
  496. BEGIN
  497. CASE xformat OF
  498. | index8:
  499. FOR i := 1 TO width DO
  500. S.GET( ip, byte ); S.PUT( bp, byte ); INC( ip ); INC( bp )
  501. END
  502. | color565, color555, color664:
  503. FOR i := 1 TO width DO
  504. S.GET( ip, byte ); S.PUT( bp + 1, byte ); INC( ip );
  505. S.GET( ip, byte ); S.PUT( bp + 0, byte ); INC( ip );
  506. INC( bp, 2 )
  507. END
  508. | color888:
  509. FOR i := 1 TO width DO
  510. INC( ip );
  511. S.GET( ip, byte ); S.PUT( bp + 2, byte ); INC( ip ); (* B *)
  512. S.GET( ip, byte ); S.PUT( bp + 1, byte ); INC( ip ); (* G *)
  513. S.GET( ip, byte ); S.PUT( bp + 0, byte ); INC( ip ); (* R *)
  514. INC( bp, 3 )
  515. END;
  516. ELSE (* color8888 *)
  517. FOR i := 1 TO width DO
  518. S.GET( ip, byte ); S.PUT( bp + 3, byte ); INC( ip ); (* X *)
  519. S.GET( ip, byte ); S.PUT( bp + 2, byte ); INC( ip ); (* B *)
  520. S.GET( ip, byte ); S.PUT( bp + 1, byte ); INC( ip ); (* G *)
  521. S.GET( ip, byte ); S.PUT( bp + 0, byte ); INC( ip ); (* R *)
  522. INC( bp, 4 )
  523. END;
  524. END;
  525. END GetLineBE;
  526. PROCEDURE NewPattern( d: Display;
  527. CONST image: ARRAY OF SET;
  528. width, height: INTEGER ): X11.Pattern;
  529. VAR
  530. pixmap: X11.Pixmap; pat: X11.PatternPtr;
  531. w, h, i, j, b, dest, srcw, destb, srci, desti: LONGINT;
  532. data: ARRAY 256*32 OF CHAR; (* 256*256 bits *)
  533. BEGIN
  534. i := 0;
  535. WHILE i < LEN( data ) DO data[i] := 0X; INC( i ) END;
  536. w := width; h := height;
  537. srcw := (width + 31) DIV 32; (* number of words in source line *)
  538. destb := (w + 7) DIV 8; (* number of bytes in dest line *)
  539. srci := (height - 1)*srcw; desti := 0;
  540. WHILE srci >= 0 DO
  541. i := 0; j := 0; b := 0; dest := 0;
  542. LOOP
  543. dest := dest DIV 2;
  544. IF b IN image[srci + j + 1] THEN INC( dest, 80H ) END;
  545. INC( b );
  546. IF b MOD 8 = 0 THEN
  547. data[desti + i] := CHR( dest ); INC( i ); dest := 0;
  548. IF i >= destb THEN EXIT END
  549. END;
  550. IF b = 32 THEN
  551. b := 0; INC( j );
  552. IF j >= srcw THEN
  553. WHILE i < destb DO data[desti + i] := 0X; INC( i ) END;
  554. EXIT
  555. END
  556. END
  557. END;
  558. INC( desti, destb ); DEC( srci, srcw )
  559. END;
  560. Machine.Acquire( Machine.X11 );
  561. pixmap := X11.CreateBitmapFromData( d.xdisp, d.primary, ADDRESSOF( data[0] ), w, h );
  562. Machine.Release( Machine.X11 );
  563. IF pixmap = 0 THEN HALT( 99 ) END;
  564. pat := S.VAL( X11.PatternPtr, Unix.malloc( SIZEOF( X11.PatternDesc ) ) );
  565. pat.x := 0; pat.y := 0; pat.w := width; pat.h := height; pat.pixmap := pixmap;
  566. RETURN S.VAL( LONGINT, pat )
  567. END NewPattern;
  568. PROCEDURE InitNames;
  569. VAR cwd: ARRAY 128 OF CHAR; i: LONGINT;
  570. BEGIN
  571. UnixFiles.GetWorkingDirectory( cwd );
  572. COPY( Machine.version, winName );
  573. Strings.Append( winName, ", Work: " ); Strings.Append( winName, cwd );
  574. COPY( winName, iconName);
  575. i := 0;
  576. WHILE iconName[i] > ' ' DO INC( i ) END;
  577. iconName[i] := 0X
  578. END InitNames;
  579. PROCEDURE getDisplayName;
  580. VAR adr: LONGINT; i: INTEGER; ch: CHAR;
  581. BEGIN
  582. Unix.GetArgval( "-display", dispname );
  583. IF dispname = "" THEN
  584. adr := Unix.getenv( ADDRESSOF( "DISPLAY" ) );
  585. IF adr # 0 THEN
  586. i := 0;
  587. REPEAT S.GET( adr, ch ); INC( adr ); dispname[i] := ch; INC( i ) UNTIL ch = 0X;
  588. ELSE dispname := ":0"
  589. END
  590. END
  591. END getDisplayName;
  592. PROCEDURE OpenX11Display( ): X11.DisplayPtr;
  593. VAR xdisp: X11.DisplayPtr; screen, depth: LONGINT;
  594. BEGIN
  595. getDisplayName;
  596. xdisp := Api.OpenDisplay( dispname );
  597. IF xdisp = 0 THEN
  598. Trace.String( "Cannot open X11 display " ); Trace.StringLn( dispname ); Unix.exit( 1 )
  599. END;
  600. screen := X11.DefaultScreen( xdisp );
  601. depth := X11.DefaultDepth( xdisp, screen );
  602. IF depth < 8 THEN
  603. Trace.StringLn( "UnixAos needs a color display. sorry." ); Unix.exit( 1 )
  604. END;
  605. Trace.String( "X11 Display depth = " ); Trace.Int( depth, 1 ); Trace.Ln;
  606. RETURN xdisp
  607. END OpenX11Display;
  608. PROCEDURE CreateColors( d: Display );
  609. VAR col: INTEGER;
  610. visualInfo: X11.VisualInfo;
  611. BEGIN
  612. Machine.Acquire( Machine.X11 );
  613. col := 0;
  614. WHILE col < 256 DO d.pixel[col] := col; INC( col ) END;
  615. IF (d.depth > 8) & (X11.MatchVisualInfo( d.xdisp, d.screen, d.depth, X11.TrueColor, visualInfo ) = 1) THEN
  616. d.visual := visualInfo.visual;
  617. ELSIF X11.MatchVisualInfo( d.xdisp, d.screen, d.depth, X11.PseudoColor, visualInfo ) = 1 THEN
  618. d.visual := visualInfo.visual
  619. END;
  620. d.bigEndian := FALSE;
  621. IF d.depth > 8 THEN
  622. d.bigEndian := d.visual.blueMask > d.visual.redMask
  623. ELSE (* pseudo color *)
  624. d.cmap := X11.CreateColormap( d.xdisp, d.primary, d.visual, X11.AllocAll );
  625. X11.SetWindowColormap( d.xdisp, d.primary, d.cmap );
  626. d.foreground := d.pixel[FG];
  627. d.background := d.pixel[BG];
  628. X11.SetWindowBackground( d.xdisp, d.primary, d.background );
  629. X11.ClearWindow( d.xdisp, d.primary )
  630. END;
  631. Machine.Release( Machine.X11 );
  632. d.planesMask := ASH( 1, d.depth ) - 1
  633. END CreateColors;
  634. PROCEDURE InitPalette( d: Display );
  635. VAR f: Files.File; r: Files.Reader; red, green, blue: CHAR; i, cols: INTEGER;
  636. BEGIN
  637. IF d.depth >= 8 THEN cols := 256 ELSE cols := 16 END;
  638. f := Files.Old( "Default.Pal" );
  639. IF f # NIL THEN
  640. Files.OpenReader( r, f, 0 );
  641. FOR i := 0 TO cols - 1 DO
  642. r.Char( red ); r.Char( green ); r.Char( blue );
  643. d.SetColor( i, ORD( red ), ORD( green ), ORD( blue ) )
  644. END
  645. END;
  646. d.defPal := d.rgb
  647. END InitPalette;
  648. PROCEDURE SuppressX11Cursors( d: Display );
  649. VAR
  650. fg, bg: X11.Color; src, msk: X11.PatternPtr;
  651. image: ARRAY 17 OF SET; i: INTEGER;
  652. noCursor: X11.Cursor;
  653. BEGIN
  654. fg.red := 256*d.rgb[FG].r; fg.green := 256*d.rgb[FG].g; fg.blue := 256*d.rgb[FG].b;
  655. bg.red := 256*d.rgb[BG].r; bg.green := 256*d.rgb[BG].g; bg.blue := 256*d.rgb[BG].b;
  656. FOR i := 1 TO 16 DO image[i] := {} END;
  657. src := S.VAL( X11.PatternPtr, NewPattern( d, image, 16, 16 ) );
  658. msk := S.VAL( X11.PatternPtr, NewPattern( d, image, 16, 16 ) );
  659. Machine.Acquire( Machine.X11 );
  660. noCursor := X11.CreatePixmapCursor( d.xdisp, src.pixmap, msk.pixmap, fg, bg, 1, 1 );
  661. X11.DefineCursor( d.xdisp, d.primary, noCursor );
  662. Machine.Release( Machine.X11 )
  663. END SuppressX11Cursors;
  664. PROCEDURE InitFormat( d: Display );
  665. BEGIN
  666. IF d.depth = 8 THEN
  667. d.format := Displays.index8;
  668. d.xformat := index8
  669. ELSIF d.depth = 15 THEN
  670. d.format := Displays.color565;
  671. d.xformat := color555
  672. ELSIF d.depth = 16 THEN
  673. d.format := Displays.color565;
  674. IF d.visual.blueMask = 0FH THEN d.xformat := color664
  675. ELSE d.xformat := color565
  676. END
  677. ELSIF d.depth = 24 THEN
  678. d.format := Displays.color888;
  679. d.xformat := color888
  680. ELSIF d.depth = 32 THEN
  681. d.format := Displays.color8888;
  682. d.xformat := color8888
  683. ELSE
  684. d.format := unknown
  685. END;
  686. END InitFormat;
  687. PROCEDURE CreateGC( d: Display );
  688. BEGIN
  689. Machine.Acquire( Machine.X11 );
  690. d.gc := X11.CreateGC( d.xdisp, d.primary, 0, 0 );
  691. IF d.gc = 0 THEN Machine.Release( Machine.X11 ); HALT( 45 ) END;
  692. X11.SetPlaneMask( d.xdisp, d.gc, d.planesMask );
  693. X11.SetGraphicsExposures( d.xdisp, d.gc, X11.True );
  694. X11.SetBackground( d.xdisp, d.gc, d.background );
  695. Machine.Release( Machine.X11 );
  696. END CreateGC;
  697. PROCEDURE InitFunctions( d: Display );
  698. BEGIN
  699. d.xfunc[replace] := X11.GXcopy;
  700. d.xfunc[paint] := X11.GXor; (* not used *)
  701. (* drawing in invert mode with BackgroundCol on BackgroundCol is a no-op: *)
  702. IF S.VAL( SET, d.background )*S.VAL( SET, d.planesMask ) # {} THEN
  703. d.xfunc[invert] := X11.GXequiv
  704. ELSE
  705. d.xfunc[invert] := X11.GXxor
  706. END;
  707. d.currcol := -1; d.currmode := -1;
  708. END InitFunctions;
  709. (* PB - 2010-04-20
  710. Return:
  711. -1: absolute width and height according to DisplaySize config string.
  712. else: value from 50 to 100 as scaling factor, argument variables width and height are unspecified.
  713. Lower limit is either 50% as scaling factor or 640x480 as absolute size.
  714. *)
  715. PROCEDURE GetDisplaySize(VAR width, height: LONGINT): LONGINT; (* % of Screen [50% ... 100%] *)
  716. VAR buf: ARRAY 64 OF CHAR; size, i: LONGINT; c: CHAR; absolute: BOOLEAN;
  717. BEGIN
  718. Machine.GetConfig( "DisplaySize", buf );
  719. IF buf = "" THEN size := 100
  720. ELSE
  721. size := 0; c := buf[0]; i := 0;
  722. WHILE (c >= '0') & (c <= '9') DO
  723. size := 10*size + ORD( c ) - ORD( '0' );
  724. INC( i ); c := buf[i]
  725. END;
  726. IF c = 'x' THEN
  727. width := size;
  728. size := 0;
  729. INC( i ); c := buf[i];
  730. END;
  731. WHILE (c >= '0') & (c <= '9') DO
  732. size := 10*size + ORD( c ) - ORD( '0' );
  733. INC( i ); c := buf[i]
  734. END;
  735. IF (width # 0) & (size # 0) THEN
  736. height := size;
  737. absolute := TRUE;
  738. ELSIF (width # 0) THEN (* failed to read two numbers -> fall back to scaling *)
  739. size := width;
  740. width := 0
  741. END;
  742. IF absolute THEN
  743. size := -1;
  744. IF width < 640 THEN width := 640; END;
  745. IF height < 480 THEN height := 480; END;
  746. ELSE
  747. IF size < 50 THEN size := 50 END;
  748. IF size > 100 THEN size := 100 END
  749. END;
  750. END;
  751. RETURN size
  752. END GetDisplaySize;
  753. PROCEDURE Install*;
  754. VAR disp: Display; res: LONGINT; s, w, h: LONGINT; xdisp: X11.DisplayPtr;
  755. BEGIN
  756. InitNames; xdisp := OpenX11Display( );
  757. s := GetDisplaySize( w, h );
  758. NEW( disp, xdisp, w, h, s, s );
  759. disp.SetName( "XDisplay" );
  760. disp.desc := "X11 display driver";
  761. Displays.registry.Add( disp, res );
  762. END Install;
  763. BEGIN
  764. NEW( imgBuffer, 10000 )
  765. END XDisplay.