2
0

WMWindowManager.Mod 40 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235
  1. MODULE WMWindowManager; (** AUTHOR "TF"; PURPOSE "Generic window manager"; *)
  2. IMPORT
  3. Modules, KernelLog, Plugins, Locks, Strings, Messages := WMMessages, Graphics := WMGraphics, Raster, Rectangles := WMRectangles;
  4. CONST
  5. FlagFrame* = 0; (** The window has a frame *)
  6. FlagClose* = 1; (** The window offers a close button; only frame windows *)
  7. FlagMinimize* = 2; (** The window offers a minimize button; only frame windows *)
  8. FlagStayOnTop* = 3; (** The window will always stay above all non stay on top windows *)
  9. FlagNonDispatched* = 4; (** The window has no message queue --> BE CAREFUL *)
  10. FlagNoFocus* = 5; (** The window can never get the keyboard focus *)
  11. FlagDecorWindow* = 6; (** The window is a decor window, associated to a master window *)
  12. FlagStayOnBottom* = 7; (** The window can not be moved up *)
  13. FlagNavigation* = 8; (** The window will always appear at the same position/size on the screen independent of the range of the viewport displaying it. *)
  14. FlagHidden* = 9; (** This flag indicates whether a window should be managed by window navigation tools. It does not influence the visibiliy or behaviour of the window *)
  15. FlagNoResizing* = 10; (** If set, window resizing is disabled *)
  16. FlagNoPointer*=11; (* if set, in window there will be no pointer visible --> touch screens *)
  17. FlagStorable*=12; (* window storable*)
  18. SizeMinHeight = 3; (* Minimum height of a window *)
  19. SizeMinWidth = 3; (* Minimum width of a window *)
  20. (* result codes for Window.OpenDocument *)
  21. Ok* = 0;
  22. Error* = 1;
  23. NotSupported* = 2;
  24. (* Window position for new windows added *)
  25. X0 = 30;
  26. Y0 = 80;
  27. TYPE
  28. Rectangle = Rectangles.Rectangle;
  29. String = Strings.String;
  30. Message = Messages.Message;
  31. RealRect* = RECORD l*, t*, r*, b* : REAL END;
  32. PointerInfo* = OBJECT
  33. VAR hotX*, hotY* : LONGINT; img* : Graphics.Image;
  34. END PointerInfo;
  35. (** All fields are read-only except for the module SkinEngine.Mod!
  36. Modifications of the instance that is owned by the window manager require
  37. the window manager write lock being held!
  38. Most of the information is used by WMDefaultWindows.Mod *)
  39. WindowStyle* = OBJECT
  40. VAR
  41. (** use bitmaps for frame windows? *)
  42. useBitmaps* : BOOLEAN;
  43. (** frame color if not using bitmaps (a = active, i = inactive) *)
  44. baCol*, biCol* : LONGINT;
  45. (** frame shading width if not using bitmaps (a = active, i = inactive) *)
  46. basw*, bisw* : LONGINT;
  47. (** height / width of frame windows th = top height, bh = bottom height, lw = left width, rw = right width *)
  48. th*, bh*, lw*, rw* : LONGINT;
  49. (** frame window bitmaps
  50. 1st letter: t = top, l = left, r = right, b = bottom decor window
  51. 2nd letter: a = active, i = inactive
  52. 3rd letter: a = left bitmap, b = middle bitmap (repeated), c = right bitmap
  53. *)
  54. taa*, tab*, tac*, tia*, tib*, tic*,
  55. laa*, lab*, lac*, lia*, lib*, lic*,
  56. raa*, rab*, rac*, ria*, rib*, ric*,
  57. baa*, bab*, bac*, bia*, bib*, bic* : Graphics.Image;
  58. (** Close and minimize button images (a = active, i = inactive) *)
  59. ca*, ci*, closeHover*,
  60. ma*, mi*, minimizeHover* : Graphics.Image;
  61. minimizeOffset* : LONGINT; (** offset correction for minimize button *)
  62. (** Window title position and color (a = active, i = inactive) *)
  63. atextX*, atextY*, atextColor*, itextX*, itextY*, itextColor* : LONGINT;
  64. bgColor*, fgColor*, selectCol*, desktopColor* : Graphics.Color;
  65. topFocusThreshold*, topThreshold*, bottomFocusThreshold*, bottomThreshold*,
  66. leftFocusThreshold*, leftThreshold*, rightFocusThreshold*, rightThreshold* : LONGINT;
  67. (* Initialize/reset to zero-style for windows *)
  68. PROCEDURE &Init*;
  69. BEGIN
  70. useBitmaps := FALSE;
  71. baCol := 0FFFFH; biCol := 0FF40H;
  72. basw := 4; bisw := 3;
  73. th := 20; bh := 3; lw := 3; rw := 3;
  74. (* images *)
  75. taa := NIL; tab := NIL; tac := NIL; tia := NIL; tib := NIL; tic := NIL;
  76. laa := NIL; lab := NIL; lac := NIL; lia := NIL; lib := NIL; lic := NIL;
  77. raa := NIL; rab := NIL; rac := NIL; ria := NIL; rib := NIL; ric := NIL;
  78. baa := NIL; bab := NIL; bac := NIL; bia := NIL; bib := NIL; bic := NIL;
  79. ca := Graphics.LoadImage("ZeroSkin.zip://aclose.png", TRUE);
  80. ci := Graphics.LoadImage("ZeroSkin.zip://iclose.png", TRUE);
  81. closeHover := NIL;
  82. ma := NIL; mi := NIL; minimizeHover := NIL;
  83. minimizeOffset := 0;
  84. (* window caption *)
  85. atextX := 5; atextY := 15; atextColor := LONGINT(0FFFF00FFH);
  86. itextX := 5; itextY := 15; itextColor := 04444FFH;
  87. (* desktop *)
  88. bgColor := LONGINT(08080FFFFH);
  89. fgColor := 0000000FFH;
  90. selectCol := 0FFFFH;
  91. desktopColor := LONGINT(08080FFFFH);
  92. topFocusThreshold := 0; topThreshold := 0;
  93. bottomFocusThreshold := 0; bottomThreshold := 0;
  94. leftFocusThreshold := 0; leftThreshold := 0;
  95. rightFocusThreshold := 0; rightThreshold := 0;
  96. END Init;
  97. (** calculate distances from images *)
  98. PROCEDURE Initialize*;
  99. BEGIN
  100. IF useBitmaps THEN
  101. IF tab # NIL THEN th := tab.height END;
  102. IF bab # NIL THEN bh := bab.height END;
  103. IF lab # NIL THEN lw := lab.width END;
  104. IF rab # NIL THEN rw := rab.width END;
  105. END
  106. END Initialize;
  107. END WindowStyle;
  108. DragInfo* = OBJECT
  109. VAR
  110. data*, sender* : ANY;
  111. onAccept*, onReject* : Messages.CompCommand;
  112. offsetX*, offsetY*: LONGINT;
  113. END DragInfo;
  114. (** List of decoration - windows to a master window *)
  115. DecorList* = OBJECT
  116. VAR next* : DecorList;
  117. w* : Window;
  118. END DecorList;
  119. (** A message preview procedure can set discard to TRUE to discard the message *)
  120. MessagePreviewProc* = PROCEDURE (VAR msg : Message; VAR discard : BOOLEAN);
  121. MessagePreviewList* = OBJECT
  122. VAR proc*: MessagePreviewProc;
  123. next*:MessagePreviewList;
  124. END MessagePreviewList;
  125. DocumentInfo* = RECORD
  126. id* : LONGINT;
  127. name* : ARRAY 32 OF CHAR; (* if name = "", this document info is not valid *)
  128. fullname* : ARRAY 256 OF CHAR;
  129. modified*, hasFocus* : BOOLEAN;
  130. END;
  131. VisualComponentInfo* = RECORD
  132. width*, height* : LONGINT; (* preferred width and height of visual component *)
  133. generator* : PROCEDURE {DELEGATE} () : ANY; (* NIL if no visual component available *)
  134. END;
  135. (** A window may provide information about currently opened documents. Additionally, it can provide a visual component that controls it. *)
  136. WindowInfo* = RECORD
  137. openDocuments* : ARRAY 16 OF DocumentInfo;
  138. handleDocumentInfo* : PROCEDURE {DELEGATE} (CONST info : DocumentInfo; new : BOOLEAN; VAR res : LONGINT);
  139. vc* : VisualComponentInfo;
  140. END;
  141. WindowInfoPtr = POINTER TO WindowInfo;
  142. Window* = OBJECT
  143. VAR
  144. id- : LONGINT;
  145. timestamp* : LONGINT; (* incremented at each call of procedure Draw *)
  146. (** Ranges in global coordinates *)
  147. bounds* : Rectangle; (** current range *)
  148. initialBounds* : Rectangle; (** range at window creation *)
  149. normalBounds* : Rectangle; (** range before toggling to fullscreen *)
  150. manager* : WindowManager;
  151. sequencer* : Messages.MsgSequencer;
  152. (** window state that may only be accessed by the window manager *)
  153. prev*, next* : Window; (** previous and next window in z order *)
  154. title : String; (* window title *)
  155. info* : WindowInfoPtr;
  156. master* : Window; (** is only set if the window is a decor window *)
  157. view* : ViewPort;
  158. decor* : DecorList;
  159. flags* : SET;
  160. icon* : Graphics.Image; (** Optional icon for Window *)
  161. topW*, bottomW*, leftW*, rightW* : Window; (** Optional decor windows *)
  162. useAlpha* : BOOLEAN;
  163. isVisible* : BOOLEAN;
  164. pointerInfo- : PointerInfo;
  165. acceptDrag : BOOLEAN;
  166. reduceQuality- : BOOLEAN;
  167. PROCEDURE &Init*(w, h : LONGINT; alpha : BOOLEAN);
  168. BEGIN
  169. id := GetId();
  170. timestamp := 0;
  171. bounds := Graphics.MakeRectangle(0, 0, w, h);
  172. initialBounds := bounds;
  173. normalBounds := bounds;
  174. manager := NIL; sequencer := NIL;
  175. prev := NIL; next := NIL;
  176. title := NIL;
  177. info := NIL;
  178. master := NIL; decor := NIL;
  179. view := NIL;
  180. flags := {};
  181. icon := NIL;
  182. topW := NIL; bottomW := NIL; leftW := NIL; rightW := NIL;
  183. useAlpha := alpha;
  184. isVisible := TRUE;
  185. pointerInfo := NIL;
  186. acceptDrag := FALSE;
  187. reduceQuality := FALSE;
  188. END Init;
  189. PROCEDURE IsCallFromSequencer*() : BOOLEAN;
  190. BEGIN
  191. RETURN (sequencer # NIL) & (sequencer.IsCallFromSequencer())
  192. END IsCallFromSequencer;
  193. (** Return the window manager that handles the window *)
  194. PROCEDURE GetManager*() : WindowManager;
  195. BEGIN
  196. RETURN manager
  197. END GetManager;
  198. (** Set the window title as UTF8 string. *)
  199. PROCEDURE SetTitle*(title : String);
  200. BEGIN
  201. IF manager # NIL THEN manager.SetWindowTitle(SELF, title) ELSE SELF.title := title END
  202. END SetTitle;
  203. (** Return the title as UTF8 string. Returns NIL if no title is set *)
  204. PROCEDURE GetTitle*() : String;
  205. BEGIN
  206. IF manager # NIL THEN RETURN manager.GetWindowTitle(SELF) ELSE RETURN title END
  207. END GetTitle;
  208. PROCEDURE SetIcon*(icon : Graphics.Image);
  209. BEGIN
  210. IF (manager # NIL) THEN manager.SetWindowIcon(SELF, icon); ELSE SELF.icon := icon; END;
  211. END SetIcon;
  212. (** Return the height in client space *) (* go via manager *)
  213. PROCEDURE GetHeight*() : LONGINT;
  214. BEGIN
  215. RETURN bounds.b - bounds.t
  216. END GetHeight;
  217. (** Return the width in client space *) (* go via manager *)
  218. PROCEDURE GetWidth*() : LONGINT;
  219. BEGIN
  220. RETURN bounds.r - bounds.l
  221. END GetWidth;
  222. PROCEDURE SetInfo*(CONST info : WindowInfo);
  223. BEGIN
  224. IF (manager # NIL) THEN
  225. manager.SetWindowInfo(SELF, info);
  226. ELSE
  227. IF (SELF.info = NIL) THEN NEW(SELF.info); END;
  228. SELF.info^ := info;
  229. END;
  230. END SetInfo;
  231. PROCEDURE GetInfo*(VAR info : WindowInfo) : BOOLEAN;
  232. VAR infoPtr : WindowInfoPtr;
  233. BEGIN
  234. IF (manager # NIL) THEN
  235. RETURN manager.GetWindowInfo(SELF, info);
  236. ELSE
  237. infoPtr := SELF.info;
  238. IF (infoPtr # NIL) THEN
  239. info := infoPtr^;
  240. END;
  241. RETURN (infoPtr # NIL);
  242. END;
  243. END GetInfo;
  244. (** Resize is called by the WM if it wants to resize the window.
  245. width and height contain the desired new size. The Window should set width and height to acceptable
  246. values or return the current size, if resize is not supported *)
  247. PROCEDURE Resizing*(VAR width, height : LONGINT);
  248. BEGIN
  249. IF FlagNoResizing IN flags THEN
  250. width := GetWidth(); height := GetHeight();
  251. ELSE
  252. IF width < SizeMinWidth THEN
  253. width := GetWidth();
  254. END;
  255. IF height < SizeMinHeight THEN
  256. height := GetHeight();
  257. END;
  258. END;
  259. END Resizing;
  260. (** May replace the back-image, if needed. MUST check if requested size is reasonable (0 < x * y < memory) *)
  261. PROCEDURE Resized*(width, height : LONGINT);
  262. END Resized;
  263. (** Invalidate a rectangle in window coordinates*)
  264. PROCEDURE Invalidate*(rect : Rectangle);
  265. BEGIN
  266. Rectangles.MoveRel(rect, bounds.l, bounds.t);
  267. Rectangles.ClipRect(rect, bounds);
  268. IF manager # NIL THEN manager.AddVisibleDirty(SELF, rect) END
  269. END Invalidate;
  270. (** Message procedures *)
  271. (** Pointer Messages *)
  272. (** PointerDown is called via the generic message handler if the pointer (or a mouse button) is pressed down and
  273. a) the pointer is in the bounding box of the window AND IsHit returns TRUE for this position
  274. or
  275. b) another mouse button was pressed down on a position where a) was met and has not yet been released.
  276. x and y are in window coordinates but may lie out of the window boundaries in case b)
  277. keys is the set of buttons that are down
  278. *)
  279. PROCEDURE PointerDown*(x, y : LONGINT; keys : SET);
  280. END PointerDown;
  281. (** PointerMove is called via the generic message handler if the pointer (mouse) is moved and
  282. a) the pointer is in the bounding box of the window AND IsHit returns TRUE for this position
  283. or
  284. b) the pointer was pressed down on a position where a) was met and has not yet been released.
  285. x and y are in window coordinates but may lie out of the window boundaries.
  286. keys is the set of buttons that are down
  287. *)
  288. PROCEDURE PointerMove*(x, y : LONGINT; keys : SET);
  289. END PointerMove;
  290. PROCEDURE WheelMove*(dz : LONGINT);
  291. END WheelMove;
  292. (** PointerUp is called via the generic message handler if the pointer (or a mouse button) went up.
  293. x and y are in window coordinates but may lie out of the window boundaries.
  294. keys is the set of buttons that are STILL DOWN
  295. *)
  296. PROCEDURE PointerUp*(x, y : LONGINT; keys : SET);
  297. END PointerUp;
  298. (** PointerLeave is called via the generic message handler if the pointer has left the window with no button pressed. *)
  299. PROCEDURE PointerLeave*;
  300. END PointerLeave;
  301. (** DragOver is called via the message handler. *)
  302. PROCEDURE DragOver*(x, y: LONGINT; dragInfo : DragInfo);
  303. END DragOver;
  304. (** Dropped is called via the message handler to indicate an item has been dropped. *)
  305. PROCEDURE DragDropped*(x, y: LONGINT; dragInfo : DragInfo);
  306. END DragDropped;
  307. (** send the srcWindow a confirmation for the completed drag operation *)
  308. PROCEDURE ConfirmDrag*(accept : BOOLEAN; dragInfo : DragInfo);
  309. BEGIN
  310. IF dragInfo # NIL THEN
  311. IF accept THEN
  312. IF dragInfo.onAccept # NIL THEN dragInfo.onAccept(SELF, dragInfo) END
  313. ELSE
  314. IF dragInfo.onReject # NIL THEN dragInfo.onReject(SELF, dragInfo) END
  315. END
  316. END
  317. END ConfirmDrag;
  318. (** Start a drag operation. *)
  319. PROCEDURE StartDrag*(sender, data : ANY; img : Graphics.Image; offsetX, offsetY: LONGINT; onAccept, onReject : Messages.CompCommand) : BOOLEAN;
  320. BEGIN
  321. RETURN manager.StartDrag(SELF, sender, data, img, offsetX, offsetY, onAccept, onReject)
  322. END StartDrag;
  323. (** Keyboard message *)
  324. (** KeyEvent is called via the generic message handler to signal a keyboard event.
  325. The window can determine wheter the key was pressed or released by examining the
  326. Inputs.Release flag in flags. ucs contains the unicode equivalent of the key. Special input editors
  327. send the generated unicode characters via KeyEvent. *)
  328. PROCEDURE KeyEvent*(ucs : LONGINT; flags : SET; keysym : LONGINT);
  329. END KeyEvent;
  330. (** Focus messages *)
  331. (** FocusGot is called via the generic message handler if the keyboard focus is transfered to this window *)
  332. PROCEDURE FocusGot*;
  333. END FocusGot;
  334. (** FocusList is called via the generic message handler if the keyboard focus is transfered to some other window *)
  335. PROCEDURE FocusLost*;
  336. END FocusLost;
  337. (** Style *)
  338. (** StyleChanged is called via the generic message handler if a change in the global style occurs. The
  339. Window should read all the style information it relies on and redraw itself *)
  340. PROCEDURE StyleChanged*;
  341. END StyleChanged;
  342. (** Closing *)
  343. PROCEDURE CanClose*() : BOOLEAN;
  344. BEGIN
  345. RETURN TRUE
  346. END CanClose;
  347. (** Close is called via the generic message handler. *)
  348. PROCEDURE Close*;
  349. BEGIN
  350. IF manager # NIL THEN manager.Remove(SELF) END;
  351. END Close;
  352. (** Return true if the window is hit at the coordinates x and y (in window coordinates). Use
  353. this to generate non-rectangular windows.
  354. This Method will be called directly by the window manager. __> Don't block, don't crash !!
  355. *)
  356. PROCEDURE IsHit*(x, y : LONGINT) : BOOLEAN;
  357. BEGIN
  358. RETURN TRUE
  359. END IsHit;
  360. PROCEDURE SetPointerInfo*(pi : PointerInfo);
  361. BEGIN
  362. IF FlagNoPointer IN flags THEN pi := pointerNull END;
  363. IF pi # pointerInfo THEN
  364. pointerInfo := pi;
  365. IF manager # NIL THEN manager.CheckPointerImage END;
  366. END
  367. END SetPointerInfo;
  368. (** Generic message handler distributes messages to the different msg-handler methods *)
  369. PROCEDURE Handle*(VAR m : Message);
  370. BEGIN
  371. IF m.msgType = Messages.MsgKey THEN
  372. KeyEvent(m.x, m.flags, m.y)
  373. ELSIF m.msgType = Messages.MsgPointer THEN
  374. (* global to local transformation by sequencer thread: *)
  375. m.x := m.x-bounds.l;
  376. m.y := m.y-bounds.t;
  377. IF m.msgSubType = Messages.MsgSubPointerMove THEN
  378. IF (m.dz # 0) THEN WheelMove(m.dz) END;
  379. PointerMove(m.x, m.y, m.flags)
  380. ELSIF m.msgSubType = Messages.MsgSubPointerDown THEN PointerDown(m.x, m.y, m.flags)
  381. ELSIF m.msgSubType = Messages.MsgSubPointerUp THEN PointerUp(m.x, m.y, m.flags)
  382. ELSIF m.msgSubType = Messages.MsgSubPointerLeave THEN PointerLeave
  383. END
  384. ELSIF m.msgType = Messages.MsgDrag THEN
  385. IF m.msgSubType = Messages.MsgDragOver THEN
  386. IF (m.ext # NIL) THEN
  387. DragOver(m.x, m.y, m.ext(DragInfo))
  388. END
  389. ELSIF m.msgSubType = Messages.MsgDragDropped THEN
  390. IF (m.ext # NIL) THEN
  391. DragDropped(m.x, m.y, m.ext(DragInfo))
  392. END
  393. END
  394. ELSIF m.msgType = Messages.MsgClose THEN Close
  395. ELSIF m.msgType = Messages.MsgFocus THEN
  396. IF m.msgSubType = Messages.MsgSubFocusGot THEN FocusGot
  397. ELSIF m.msgSubType = Messages.MsgSubFocusLost THEN FocusLost
  398. END
  399. ELSIF m.msgType = Messages.MsgStyleChanged THEN StyleChanged
  400. ELSIF m.msgType = Messages.MsgResized THEN Resized(m.x, m.y)
  401. END;
  402. END Handle;
  403. (** Draw request form the window manager. The canvas becomes invalid when the method ends. The
  404. draw method may not modify window or WindowManager properties.
  405. w, h is the area in view coordinates, q is the Quality 0 lowest 1 mid 2 high. A window may ignore q *)
  406. PROCEDURE Draw*(canvas : Graphics.Canvas; w, h, q : LONGINT);
  407. END Draw;
  408. (** Is called by the windowmanager with reduce set, if the window is resized or moved on slow machines *)
  409. PROCEDURE HintReduceQuality*(reduce : BOOLEAN);
  410. BEGIN
  411. IF reduce # reduceQuality THEN
  412. reduceQuality := reduce;
  413. IF ~reduceQuality THEN
  414. IF manager # NIL THEN manager.AddVisibleDirty(SELF, bounds) END
  415. END
  416. END
  417. END HintReduceQuality;
  418. END Window;
  419. (** assumes the window is size agnostic, handles all the zooming issues directly *)
  420. BufferWindow* = OBJECT(Window)
  421. VAR
  422. img* : Graphics.Image;
  423. canvas* : Graphics.BufferCanvas;
  424. canvasGen-: Graphics.CanvasGenerator;
  425. pointerThreshold*,
  426. maxInterpolation* : LONGINT; (* allows limiting the interpolation degree on Draw *)
  427. PROCEDURE &Init*(w, h : LONGINT; alpha : BOOLEAN);
  428. BEGIN
  429. Init^(w, h, alpha);
  430. NEW(img);
  431. IF alpha THEN Raster.Create(img, w, h, Raster.BGRA8888) ELSE Raster.Create(img, w, h, format) END;
  432. SetCanvasGenerator(Graphics.GenCanvas);
  433. pointerThreshold := 1; (* invisible pixels are treated as invisible *)
  434. maxInterpolation := Graphics.ScaleBilinear;
  435. END Init;
  436. PROCEDURE SetCanvasGenerator*(canvasGen:Graphics.CanvasGenerator);
  437. BEGIN{EXCLUSIVE}
  438. SELF.canvasGen:=canvasGen; IF img # NIL THEN canvas:=canvasGen(img); END;
  439. IF manager # NIL THEN manager.AddVisibleDirty(SELF, bounds) END
  440. END SetCanvasGenerator;
  441. PROCEDURE IsHit(x, y : LONGINT) : BOOLEAN;
  442. VAR w, h : LONGINT; fx, fy : REAL;
  443. BEGIN
  444. w := GetWidth(); h := GetHeight();
  445. IF (w > 0) & (h > 0) & ((w # img.width) OR (h # img.height)) THEN
  446. fx := img.width / w; fy := img.height / h;
  447. RETURN Graphics.IsBitmapHit(ENTIER(x * fx), ENTIER(y * fy), pointerThreshold, img)
  448. ELSE RETURN Graphics.IsBitmapHit(x, y, pointerThreshold, img)
  449. END
  450. END IsHit;
  451. PROCEDURE Draw*(canvas : Graphics.Canvas; w, h, q : LONGINT);
  452. VAR img: Graphics.Image;
  453. BEGIN
  454. img := SELF.img;
  455. IF reduceQuality THEN q := 0 END;
  456. IF img # NIL THEN
  457. IF (w = img.width) & (h = img.height) THEN
  458. IF useAlpha THEN canvas.DrawImage(0, 0, img, Graphics.ModeSrcOverDst)
  459. ELSE canvas.DrawImage(0, 0, img, Graphics.ModeCopy)
  460. END
  461. ELSE
  462. IF useAlpha THEN
  463. canvas.ScaleImage(img, Rectangles.MakeRect(0, 0, img.width, img.height),
  464. Rectangles.MakeRect(0, 0, w, h), Graphics.ModeSrcOverDst, MIN( q,maxInterpolation))
  465. ELSE
  466. canvas.ScaleImage(img, Rectangles.MakeRect(0, 0, img.width, img.height),
  467. Rectangles.MakeRect(0, 0, w, h), Graphics.ModeCopy, MIN(q,maxInterpolation))
  468. END
  469. END
  470. END;
  471. INC(timestamp);
  472. END Draw;
  473. PROCEDURE Invalidate*(rect : Rectangle);
  474. VAR w, h : LONGINT; fx, fy : REAL;
  475. BEGIN
  476. w := GetWidth(); h := GetHeight();
  477. IF (w > 0) & (h > 0) & ((w # img.width) OR (h # img.height)) THEN
  478. fx := w / img.width; fy := h / img.height;
  479. rect.l := ENTIER(rect.l * fx); rect.t := ENTIER(rect.t * fy);
  480. rect.r := ENTIER(rect.r * fx + 0.5); rect.b := ENTIER(rect.b * fy + 0.5)
  481. END;
  482. Invalidate^(rect)
  483. END Invalidate;
  484. PROCEDURE Handle*(VAR m : Message);
  485. VAR w, h : LONGINT; fx, fy : REAL;
  486. BEGIN
  487. w := GetWidth(); h := GetHeight();
  488. IF (w > 0) & (h > 0) & ((w # img.width) OR (h # img.height)) & (m.msgType = Messages.MsgPointer) THEN
  489. m.x := m.x-bounds.l; m.y := m.y-bounds.t;
  490. fx := img.width / w; fy := img.height / h; m.x := ENTIER(m.x * fx); m.y := ENTIER(m.y * fy);
  491. m.x := m.x + bounds.l; m.y := m.y+bounds.l;
  492. END;
  493. Handle^(m)
  494. END Handle;
  495. END BufferWindow;
  496. DoubleBufferWindow* = OBJECT(BufferWindow)
  497. VAR
  498. visibleCanvas : Graphics.BufferCanvas;
  499. backImg* : Graphics.Image;
  500. swapping, drawing : BOOLEAN;
  501. PROCEDURE &Init*(w, h: LONGINT; alpha : BOOLEAN);
  502. BEGIN
  503. NEW(backImg);
  504. IF alpha THEN Raster.Create(backImg, w, h, Raster.BGRA8888) ELSE Raster.Create(backImg, w, h, format) END;
  505. Init^(w, h, alpha);
  506. END Init;
  507. PROCEDURE ReInit*(w, h : LONGINT);
  508. BEGIN {EXCLUSIVE}
  509. AWAIT(~drawing);
  510. IF useAlpha THEN
  511. Raster.Create(img, w, h, Raster.BGRA8888);
  512. Raster.Create(backImg, w, h, Raster.BGRA8888)
  513. ELSE
  514. Raster.Create(img, w, h, format);
  515. Raster.Create(backImg, w, h, format)
  516. END;
  517. visibleCanvas:=canvasGen(img);
  518. canvas:=canvasGen(backImg);
  519. END ReInit;
  520. PROCEDURE SetCanvasGenerator*(canvasGen:Graphics.CanvasGenerator);
  521. BEGIN
  522. SELF.canvasGen:=canvasGen;
  523. IF img # NIL THEN visibleCanvas:=canvasGen(img); END;
  524. IF backImg # NIL THEN canvas:=canvasGen(backImg); END;
  525. IF manager # NIL THEN manager.AddVisibleDirty(SELF, bounds) END
  526. END SetCanvasGenerator;
  527. PROCEDURE Draw*(canvas : Graphics.Canvas; w, h, q : LONGINT);
  528. BEGIN
  529. BEGIN{EXCLUSIVE}
  530. AWAIT(~swapping); drawing := TRUE;
  531. END;
  532. IF reduceQuality THEN q := 0 END;
  533. IF img # NIL THEN
  534. IF (w = img.width) & (h = img.height) THEN
  535. IF useAlpha THEN canvas.DrawImage(0, 0, img, Graphics.ModeSrcOverDst)
  536. ELSE canvas.DrawImage(0, 0, img, Graphics.ModeCopy)
  537. END
  538. ELSE
  539. IF useAlpha THEN
  540. canvas.ScaleImage(img, Rectangles.MakeRect(0, 0, img.width, img.height),
  541. Rectangles.MakeRect(0, 0, w, h), Graphics.ModeSrcOverDst, MIN(q,maxInterpolation))
  542. ELSE
  543. canvas.ScaleImage(img, Rectangles.MakeRect(0, 0, img.width, img.height),
  544. Rectangles.MakeRect(0, 0, w, h), Graphics.ModeCopy, MIN(q,maxInterpolation))
  545. END
  546. END
  547. END;
  548. BEGIN{EXCLUSIVE}
  549. drawing := FALSE;
  550. END;
  551. INC(timestamp);
  552. END Draw;
  553. PROCEDURE CopyRect*(rect : Rectangle);
  554. BEGIN {EXCLUSIVE}
  555. swapping := TRUE;
  556. AWAIT(~drawing);
  557. visibleCanvas.SetClipRect(rect);
  558. visibleCanvas.DrawImage(0, 0, backImg, Graphics.ModeCopy);
  559. visibleCanvas.SetClipRect(visibleCanvas.limits);
  560. swapping := FALSE
  561. END CopyRect;
  562. PROCEDURE Swap*;
  563. VAR tmp : Graphics.Image; tmpc : Graphics.BufferCanvas;
  564. BEGIN {EXCLUSIVE}
  565. swapping := TRUE;
  566. AWAIT(~drawing);
  567. tmp := img; img := backImg; backImg := tmp;
  568. tmpc := canvas; canvas := visibleCanvas; visibleCanvas := tmpc;
  569. swapping := FALSE
  570. END Swap;
  571. END DoubleBufferWindow;
  572. (** A ViewPort observes the global coordinate space. The WindowManager calls the view on all changes that occur
  573. in the observed range. *)
  574. ViewPort* = OBJECT (Plugins.Plugin)
  575. VAR
  576. next* : ViewPort;
  577. manager* : WindowManager;
  578. range* : RealRect;
  579. (* Width and height of viewport at 1:1 zoom. Will be set once in the constructor of the ViewPort implementation *)
  580. width0*, height0* : LONGINT; (* read-only! *)
  581. (** The WindowManager calls the Update Procedure in locked state. *)
  582. PROCEDURE Update*(r : Rectangle; top : Window);
  583. END Update;
  584. (** The WindowManager calls the Update Procedure in locked state. *)
  585. PROCEDURE Refresh*(top : Window);
  586. END Refresh;
  587. (** Set the observed range *)
  588. PROCEDURE SetRange*(x, y, w, h : REAL; showTransition : BOOLEAN);
  589. END SetRange;
  590. (** Return the modifier keys that are pressed in the view *)
  591. PROCEDURE GetKeyState*(VAR state : SET);
  592. END GetKeyState;
  593. END ViewPort;
  594. Decorator* = PROCEDURE {DELEGATE} (w : Window);
  595. WindowManager* = OBJECT(Plugins.Plugin)
  596. VAR
  597. pointerNull*, pointerStandard*, pointerMove*, pointerText*, pointerCrosshair*,
  598. pointerLeftRight*, pointerUpDown*, pointerULDR*, pointerURDL*, pointerLink* : PointerInfo;
  599. decorate* : Decorator;
  600. viewRegistry- : Plugins.Registry;
  601. sequencer- : Messages.MsgSequencer; (** PROTECTED *)
  602. lock- : Locks.RWLock; (** PROTECTED *)
  603. messagePreviewList : MessagePreviewList;
  604. style : WindowStyle;
  605. PROCEDURE &Init*;
  606. BEGIN
  607. NEW(pointerNull);
  608. InitCursors;
  609. decorate := NIL;
  610. NEW(viewRegistry, "View#", "Views Port Window Manager");
  611. NEW(sequencer, Handle); lock := sequencer.lock;
  612. messagePreviewList := NIL;
  613. NEW(style);
  614. END Init;
  615. PROCEDURE InitCursors;
  616. BEGIN
  617. LoadCursor("ZeroSkin.zip://arrow.png", 0, 0, pointerStandard);
  618. LoadCursor("ZeroSkin.zip://move.png", 15, 15, pointerMove);
  619. LoadCursor("ZeroSkin.zip://text.png", 13, 12, pointerText);
  620. LoadCursor("ZeroSkin.zip://crosshair.png", 13, 12, pointerCrosshair);
  621. LoadCursor("ZeroSkin.zip://leftright.png", 13, 12, pointerLeftRight);
  622. LoadCursor("ZeroSkin.zip://updown.png", 13, 12, pointerUpDown);
  623. LoadCursor("ZeroSkin.zip://uldr.png", 13, 12, pointerULDR);
  624. LoadCursor("ZeroSkin.zip://urdl.png", 13, 12, pointerURDL);
  625. LoadCursor("ZeroSkin.zip://hand.png", 6, 0, pointerLink);
  626. END InitCursors;
  627. PROCEDURE ZeroSkin*;
  628. BEGIN
  629. lock.AcquireWrite;
  630. style.Init;
  631. SetStyle(style);
  632. InitCursors;
  633. lock.ReleaseWrite
  634. END ZeroSkin;
  635. PROCEDURE ShutDown*;
  636. BEGIN
  637. ASSERT(lock.HasWriteLock());
  638. Plugins.main.Remove(viewRegistry)
  639. END ShutDown;
  640. (** Window management *)
  641. (** Add adds a window at pos l, t with flags *)
  642. PROCEDURE Add*(l, t : LONGINT; item : Window; flags:SET);
  643. END Add;
  644. (** Remove removes a window *)
  645. PROCEDURE Remove*(item : Window);
  646. END Remove;
  647. (** Set the position of a window *)
  648. PROCEDURE SetWindowPos*(vs : Window; x, y : LONGINT);
  649. END SetWindowPos;
  650. (** Set the size of a window. Return the new size in width and height *)
  651. (** If the window contains left, top, right or bottom, SetWindowSize is called
  652. appropriately *)
  653. PROCEDURE SetWindowSize*(vs : Window; VAR width, height : LONGINT);
  654. END SetWindowSize;
  655. (** Add a region to be refreshed *)
  656. PROCEDURE AddDirty*(VAR rect:Rectangle);
  657. END AddDirty;
  658. (** Add a dirty region. The region is in window coordinates and will be clipped against non transparent
  659. windows above *)
  660. PROCEDURE AddVisibleDirty*(w : Window; rect : Rectangle);
  661. END AddVisibleDirty;
  662. (** Set the keyboard focus to the window w *)
  663. PROCEDURE SetFocus*(w : Window);
  664. END SetFocus;
  665. (** Add a decoration window w to window to. The window w must separately be added to the wm *)
  666. (** A window MUST NOT be added more than once *)
  667. (** MUST hold lock *)
  668. PROCEDURE AddDecorWindow*(to, decor : Window);
  669. VAR dl : DecorList;
  670. BEGIN
  671. lock.AcquireWrite;
  672. INCL(decor.flags, FlagDecorWindow);
  673. INCL(decor.flags, FlagHidden);
  674. decor.master := to;
  675. NEW(dl); dl.w := decor; dl.next := to.decor; to.decor := dl;
  676. lock.ReleaseWrite
  677. END AddDecorWindow;
  678. (** Remove a decoration window w from window from. The window w must separately be removed from the wm *)
  679. (** MUST hold lock *)
  680. PROCEDURE RemoveDecorWindow*(w, from : Window);
  681. VAR dl : DecorList;
  682. BEGIN
  683. lock.AcquireWrite;
  684. IF (from.decor # NIL) & (from.decor.w = w) THEN from.decor := from.decor.next
  685. ELSE
  686. dl := from.decor;
  687. WHILE (dl.next # NIL) & (dl.next.w # w) DO dl := dl.next END;
  688. IF dl.next # NIL THEN dl.next := dl.next.next END
  689. END;
  690. lock.ReleaseWrite
  691. END RemoveDecorWindow;
  692. PROCEDURE SetStyle*(x : WindowStyle);
  693. VAR m : Message;
  694. BEGIN
  695. ASSERT(style # NIL);
  696. style := x; m.msgType := Messages.MsgStyleChanged; m.ext := style;
  697. Broadcast(m)
  698. END SetStyle;
  699. PROCEDURE GetStyle*() : WindowStyle;
  700. BEGIN
  701. ASSERT(style # NIL);
  702. RETURN style
  703. END GetStyle;
  704. (** Move Window w to front. If FlagStayOnTop is not set in w.flags, w will stay behind all windows with this flag set *)
  705. PROCEDURE ToFront*(w : Window);
  706. END ToFront;
  707. (** Move Window w to the background. If FlagStayOnTop is not set in w.flags, w will stay behind all windows *)
  708. PROCEDURE ToBack*(w : Window);
  709. END ToBack;
  710. PROCEDURE SetIsVisible*(w : Window; isVisible : BOOLEAN);
  711. VAR d : DecorList;
  712. BEGIN
  713. ASSERT(w # NIL);
  714. lock.AcquireWrite;
  715. IF (w.isVisible # isVisible) THEN
  716. w.isVisible := isVisible;
  717. IF (w.leftW # NIL) THEN w.leftW.isVisible := isVisible; END;
  718. IF (w.rightW # NIL) THEN w.rightW.isVisible := isVisible; END;
  719. IF (w.topW # NIL) THEN w.topW.isVisible := isVisible; END;
  720. IF (w.bottomW # NIL) THEN w.bottomW.isVisible := isVisible; END;
  721. AddDirty(w.bounds);
  722. IF (w.decor # NIL) THEN
  723. d := w.decor;
  724. WHILE (d # NIL) & (d.w # NIL) DO
  725. AddDirty(d.w.bounds);
  726. d := d.next;
  727. END;
  728. END;
  729. IncOTimestamp;
  730. END;
  731. lock.ReleaseWrite;
  732. END SetIsVisible;
  733. (** Set icon for a given window. Icon may be set to NIL. *)
  734. PROCEDURE SetWindowIcon*(w : Window; icon : Graphics.Image);
  735. VAR tw : Window;
  736. BEGIN
  737. ASSERT(w # NIL);
  738. lock.AcquireWrite;
  739. w.icon := icon;
  740. tw := w.topW;
  741. IF tw # NIL THEN AddVisibleDirty(tw, tw.bounds) END;
  742. lock.ReleaseWrite;
  743. IncOTimestamp;
  744. END SetWindowIcon;
  745. (** Return the window at postition x, y in global space. *)
  746. (** Windows that have the FlagNavigate flag set will not be considered *)
  747. (** Must hold WM lock *)
  748. PROCEDURE GetPositionOwner*(x, y : LONGINT) : Window;
  749. END GetPositionOwner;
  750. PROCEDURE GetFocusOwner*() : Window;
  751. END GetFocusOwner;
  752. (** Set the title of a window as UTF-8 string *)
  753. PROCEDURE SetWindowTitle*(w : Window; title : String);
  754. VAR tw : Window;
  755. BEGIN
  756. lock.AcquireWrite;
  757. w.title := title;
  758. tw := w.topW;
  759. IF tw # NIL THEN AddVisibleDirty(tw, tw.bounds) END;
  760. lock.ReleaseWrite;
  761. IncWTimestamp; (* since navigation elements care about window title *)
  762. END SetWindowTitle;
  763. (** Get the title of a window as UTF-8 string *)
  764. PROCEDURE GetWindowTitle*(w : Window) : String;
  765. BEGIN
  766. RETURN w.title
  767. END GetWindowTitle;
  768. PROCEDURE SetWindowInfo*(w : Window; CONST info : WindowInfo);
  769. BEGIN
  770. ASSERT(w # NIL);
  771. lock.AcquireWrite;
  772. IF (w.info = NIL) THEN NEW(w.info); END;
  773. w.info^ := info;
  774. lock.ReleaseWrite;
  775. IncOTimestamp;
  776. END SetWindowInfo;
  777. PROCEDURE GetWindowInfo*(w : Window; VAR info : WindowInfo) : BOOLEAN;
  778. VAR infoPtr : WindowInfoPtr;
  779. BEGIN
  780. ASSERT(w # NIL);
  781. lock.AcquireRead;
  782. infoPtr := w.info;
  783. IF (infoPtr # NIL) THEN
  784. info := infoPtr^;
  785. END;
  786. lock.ReleaseRead;
  787. RETURN (infoPtr # NIL);
  788. END GetWindowInfo;
  789. (** Set or unset a window flag
  790. Note: Setting FlagStayOnTop unsets FlagStayOnBottom and vice versa *)
  791. PROCEDURE SetWindowFlag*(w : Window; flag : LONGINT; value : BOOLEAN);
  792. BEGIN
  793. ASSERT(w # NIL);
  794. ASSERT((flag = FlagFrame) OR (flag = FlagStayOnTop) OR (flag = FlagStayOnBottom) OR (flag = FlagHidden));
  795. END SetWindowFlag;
  796. (** Set if the window is willing to accept a dropped item *)
  797. PROCEDURE SetAcceptDrag*(w : Window; accept : BOOLEAN);
  798. BEGIN
  799. lock.AcquireWrite;
  800. w.acceptDrag := accept;
  801. lock.ReleaseWrite
  802. END SetAcceptDrag;
  803. PROCEDURE StartDrag*(w : Window; sender, data : ANY; img : Graphics.Image; offsetX, offsetY: LONGINT; onAccept, onReject : Messages.CompCommand) : BOOLEAN;
  804. END StartDrag;
  805. (** a pointer button must be pressed *)
  806. PROCEDURE TransferPointer*( to : Window) : BOOLEAN;
  807. END TransferPointer;
  808. (** Adjust pointer to new position / check picture *)
  809. PROCEDURE CheckPointerImage*;
  810. END CheckPointerImage;
  811. (** View management *)
  812. (** Add a view *)
  813. PROCEDURE AddView*(v : ViewPort);
  814. END AddView;
  815. (** Add the whole View.range as dirty and cause a redraw *)
  816. PROCEDURE RefreshView*(v : ViewPort);
  817. END RefreshView;
  818. (** RemoveView from windowmanager *)
  819. PROCEDURE RemoveView*(v : ViewPort);
  820. END RemoveView;
  821. (** Messages *)
  822. PROCEDURE Broadcast*(VAR m : Message);
  823. END Broadcast;
  824. PROCEDURE SendMessage*(dest : Window; VAR m : Message) : BOOLEAN;
  825. BEGIN
  826. IF dest.sequencer # NIL THEN RETURN dest.sequencer.Add(m)
  827. ELSE dest.Handle(m); RETURN TRUE
  828. END
  829. END SendMessage;
  830. (** Install a message preview procedure. The window manager calls the MessagePreviewProc for
  831. all external messages so that they can be recorded, changed or discarded *)
  832. PROCEDURE InstallMessagePreview*(x : MessagePreviewProc);
  833. VAR mpl : MessagePreviewList;
  834. BEGIN
  835. lock.AcquireWrite;
  836. NEW(mpl); mpl.next := messagePreviewList; mpl.proc := x; messagePreviewList := mpl;
  837. lock.ReleaseWrite
  838. END InstallMessagePreview;
  839. (** Remove a MessagePreviewProc *)
  840. PROCEDURE RemoveMessagePreview*(x : MessagePreviewProc);
  841. VAR cur : MessagePreviewList;
  842. BEGIN
  843. lock.AcquireWrite;
  844. IF (messagePreviewList # NIL) & (messagePreviewList.proc = x) THEN messagePreviewList := messagePreviewList.next
  845. ELSE
  846. cur := messagePreviewList;
  847. WHILE cur # NIL DO
  848. IF (cur.next # NIL) & (cur.next.proc = x) THEN cur.next := cur.next.next; lock.ReleaseWrite; RETURN
  849. ELSE cur := cur.next END
  850. END
  851. END;
  852. lock.ReleaseWrite
  853. END RemoveMessagePreview;
  854. (** Preview message to all installed message preview handlers. Only to be used by WindowManager itself *)
  855. PROCEDURE PreviewMessage*(VAR m : Message; VAR discard : BOOLEAN); (* protected *)
  856. VAR mpl : MessagePreviewList;
  857. BEGIN
  858. ASSERT(lock.HasReadLock());
  859. discard := FALSE;
  860. mpl := messagePreviewList;
  861. WHILE (mpl # NIL) & ~discard DO mpl.proc(m, discard); mpl := mpl.next END;
  862. END PreviewMessage;
  863. (** Enumeration *)
  864. (** Get the first "user" window --> May return NIL if only background and pointer window are installed *)
  865. (** Must hold lock *)
  866. PROCEDURE GetFirst*() : Window;
  867. END GetFirst;
  868. (** Get the window next "user" window on top of x *)
  869. PROCEDURE GetNext*(x : Window) : Window;
  870. END GetNext;
  871. (** Get the "user" window below x *)
  872. PROCEDURE GetPrev*(x : Window) : Window;
  873. END GetPrev;
  874. (** Replace the background window with w. Return the current background window *)
  875. PROCEDURE ReplaceBackground*(w : Window) : Window;
  876. END ReplaceBackground;
  877. (** Return the area that is actually occupied *)
  878. PROCEDURE GetPopulatedArea*(VAR r : Rectangle);
  879. END GetPopulatedArea;
  880. (** Internal handler for message that are directed to the window manager never call directly ! *)
  881. PROCEDURE HandleInternal*(VAR msg : Messages.Message); (** PROTECTED *)
  882. BEGIN
  883. ASSERT(sequencer.IsCallFromSequencer())
  884. END HandleInternal;
  885. (** All external events of the window manager are inserted here *)
  886. PROCEDURE Handle*(VAR msg : Messages.Message);
  887. VAR discard : BOOLEAN;
  888. BEGIN
  889. IF sequencer.IsCallFromSequencer() THEN
  890. PreviewMessage(msg, discard);
  891. IF ~discard THEN HandleInternal(msg) END
  892. ELSE
  893. IF ~sequencer.Add(msg) THEN
  894. KernelLog.String("A message sent to the WM could not be handled "); KernelLog.Ln
  895. END
  896. END
  897. END Handle;
  898. END WindowManager;
  899. VAR
  900. registry- : Plugins.Registry;
  901. pointerNull: PointerInfo;
  902. (* Changes whenever a Window is added or removed to/from a WindowManager *)
  903. wTimestamp- : LONGINT;
  904. (* Changes whenever the keyboard focus is given to another window or the visibility of a window changed *)
  905. oTimestamp- : LONGINT;
  906. (* Coordinate offsets use to determine position of a new window *)
  907. x1, y1 : LONGINT;
  908. format* : Raster.Format;
  909. nextId : LONGINT;
  910. standardCursorImage: Graphics.Image;
  911. (* Get a unique identifier *)
  912. PROCEDURE GetId() : LONGINT;
  913. BEGIN {EXCLUSIVE}
  914. INC(nextId);
  915. RETURN nextId;
  916. END GetId;
  917. PROCEDURE IncWTimestamp*;
  918. BEGIN {EXCLUSIVE}
  919. INC(wTimestamp);
  920. END IncWTimestamp;
  921. PROCEDURE IncOTimestamp*;
  922. BEGIN {EXCLUSIVE}
  923. INC(oTimestamp);
  924. END IncOTimestamp;
  925. (** Block until a window is added/removed, changes its visibility or the keyboard focus changes *)
  926. PROCEDURE AwaitChange*(wTs, oTs : LONGINT);
  927. BEGIN {EXCLUSIVE}
  928. AWAIT((wTimestamp # wTs) OR (oTimestamp # oTs));
  929. END AwaitChange;
  930. PROCEDURE ClearInfo*(VAR info : WindowInfo);
  931. VAR i : LONGINT;
  932. BEGIN
  933. FOR i := 0 TO LEN(info.openDocuments)-1 DO
  934. info.openDocuments[i].id := 0;
  935. info.openDocuments[i].name := "";
  936. info.openDocuments[i].fullname := "";
  937. info.openDocuments[i].modified := FALSE;
  938. info.openDocuments[i].hasFocus := FALSE;
  939. END;
  940. info.handleDocumentInfo := NIL;
  941. info.vc.width := 0;
  942. info.vc.height := 0;
  943. info.vc.generator := NIL;
  944. END ClearInfo;
  945. PROCEDURE NewString*(CONST x : ARRAY OF CHAR) : String;
  946. VAR t : String;
  947. BEGIN
  948. NEW(t, LEN(x)); COPY(x, t^); RETURN t
  949. END NewString;
  950. PROCEDURE LoadCursor*(CONST name : ARRAY OF CHAR; hx, hy : LONGINT; VAR pi : PointerInfo);
  951. BEGIN
  952. IF pi = NIL THEN NEW(pi) END;
  953. pi.img := Graphics.LoadImage(name, TRUE); pi.hotX := hx; pi.hotY := hy;
  954. IF pi.img = NIL THEN
  955. KernelLog.String("Picture not loaded : "); KernelLog.String(name); KernelLog.Ln;
  956. IF standardCursorImage = NIL THEN CreateStandardCursorImage END;
  957. pi.img := standardCursorImage; pi.hotX := 0; pi.hotY := 0;
  958. END
  959. END LoadCursor;
  960. PROCEDURE GetDefaultManager*() : WindowManager;
  961. VAR p : Plugins.Plugin;
  962. BEGIN
  963. p := registry.Await("");
  964. RETURN p(WindowManager)
  965. END GetDefaultManager;
  966. PROCEDURE GetDefaultView*() : ViewPort;
  967. VAR p : Plugins.Plugin; m : WindowManager;
  968. BEGIN
  969. m := GetDefaultManager();
  970. p := m.viewRegistry.Await("");
  971. RETURN p(ViewPort)
  972. END GetDefaultView;
  973. PROCEDURE ResetNextPosition*;
  974. BEGIN {EXCLUSIVE}
  975. x1 := 0; y1 := 0;
  976. END ResetNextPosition;
  977. PROCEDURE GetNextPosition*(window : Window; manager : WindowManager; view : ViewPort; VAR dx, dy : LONGINT);
  978. VAR style : WindowStyle; x, y : LONGINT;
  979. BEGIN {EXCLUSIVE}
  980. ASSERT((window # NIL) & (manager # NIL) & (view # NIL));
  981. style := manager.GetStyle();
  982. x := style.lw; y := style.th;
  983. dx := x + X0 + x1; dy := y + Y0 + y1;
  984. INC(x1, x); INC(y1, y);
  985. IF (x1 > ENTIER(0.3 * view.width0)) OR (y1 > ENTIER(0.3 * view.height0)) THEN
  986. x1 := 0; y1 := 0;
  987. END;
  988. END GetNextPosition;
  989. PROCEDURE DefaultAddWindow*(w : Window);
  990. VAR manager : WindowManager; view : ViewPort; dy, dx : LONGINT;
  991. BEGIN
  992. manager := GetDefaultManager();
  993. view := GetDefaultView();
  994. GetNextPosition(w, manager, view, dx, dy);
  995. manager.Add(ENTIER(view.range.l) + dx, ENTIER(view.range.t) + dy, w, {FlagFrame, FlagClose, FlagMinimize});
  996. manager.SetFocus(w)
  997. END DefaultAddWindow;
  998. PROCEDURE AddWindow*(w : Window; dx, dy : LONGINT);
  999. VAR manager : WindowManager; view : ViewPort;
  1000. BEGIN
  1001. manager := GetDefaultManager();
  1002. view := GetDefaultView();
  1003. manager.Add(ENTIER(view.range.l) + dx, ENTIER(view.range.t) + dy, w, {FlagFrame, FlagClose, FlagMinimize})
  1004. END AddWindow;
  1005. PROCEDURE ExtAddWindow*(w : Window; dx, dy : LONGINT; flags : SET);
  1006. VAR manager : WindowManager; view : ViewPort;
  1007. BEGIN
  1008. manager := GetDefaultManager();
  1009. view := GetDefaultView();
  1010. manager.Add(ENTIER(view.range.l) + dx, ENTIER(view.range.t) + dy, w, flags)
  1011. END ExtAddWindow;
  1012. PROCEDURE ExtAddViewBoundWindow*(w : Window; dx, dy : LONGINT; view : ViewPort; flags : SET);
  1013. VAR manager : WindowManager;
  1014. BEGIN
  1015. flags := flags + {FlagNavigation};
  1016. manager := GetDefaultManager();
  1017. manager.Add(dx, dy, w, flags);
  1018. END ExtAddViewBoundWindow;
  1019. (** move a window to the default view *)
  1020. PROCEDURE DefaultBringToView*(w : Window; toFront : BOOLEAN);
  1021. VAR manager : WindowManager; view : ViewPort; dy, dx : LONGINT;
  1022. BEGIN
  1023. manager := GetDefaultManager();
  1024. view := GetDefaultView();
  1025. GetNextPosition(w, manager, view, dx, dy);
  1026. manager.SetWindowPos(w, ENTIER(view.range.l) + dx, ENTIER(view.range.t) + dy);
  1027. manager.SetFocus(w);
  1028. IF toFront THEN manager.ToFront(w) END
  1029. END DefaultBringToView;
  1030. PROCEDURE CleanUp;
  1031. BEGIN
  1032. Plugins.main.Remove(registry)
  1033. END CleanUp;
  1034. PROCEDURE CreateStandardCursorImage;
  1035. CONST Width = 32; Height = 32;
  1036. VAR canvas: Graphics.BufferCanvas; rect: Rectangles.Rectangle; points: ARRAY 3 OF Graphics.Point2d;
  1037. BEGIN
  1038. NEW(standardCursorImage);
  1039. Raster.Create(standardCursorImage, Width, Height, Raster.BGRA8888);
  1040. NEW(canvas, standardCursorImage);
  1041. Rectangles.SetRect (rect, 0, 0, Width, Height);
  1042. canvas.Fill(rect, 0H, Graphics.ModeCopy);
  1043. points[0].x := Width; points[0].y := Height DIV 2;
  1044. points[1].x := 0; points[1].y := 0;
  1045. points[2].x := Width DIV 2; points[2].y := Height;
  1046. canvas.FillPolygonFlat(points, 3, Graphics.White - 080H, Graphics.ModeCopy);
  1047. canvas.PolyLine(points, 3, FALSE, Graphics.Black, Graphics.ModeCopy);
  1048. END CreateStandardCursorImage;
  1049. BEGIN
  1050. Modules.InstallTermHandler(CleanUp);
  1051. NEW(registry, "WM#", "Window Managers");
  1052. nextId := 0; x1 := 0; y1 := 0;
  1053. wTimestamp := 0; oTimestamp := 0;
  1054. format := Raster.BGRA8888;
  1055. NEW(pointerNull);
  1056. standardCursorImage := NIL;
  1057. END WMWindowManager.