gpm.pp 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980
  1. {
  2. $Id$
  3. This file is part of the Free Pascal run time library.
  4. Copyright (c) 1999-2000 by Peter Vreman
  5. GPM (>v1.17) mouse Interface for linux
  6. See the file COPYING.FPC, included in this distribution,
  7. for details about the copyright.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY;without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. **********************************************************************}
  12. unit gpm;
  13. {Note: Libgpm is *the* interface for Linux text-mode programs.
  14. Unfortunately it isn't suitable for anything else besides a blocky
  15. cursor on a text mode interface. The GPM protocol suffers from serious
  16. defficiencies and ideally, gpm is abolished as quickly as possible.
  17. With lack of a good alternative, GPM deserves good support. But
  18. please keep this in mind while coding.}
  19. {*****************************************************************************}
  20. interface
  21. {*****************************************************************************}
  22. uses
  23. baseUnix;
  24. {$ifndef use_external}
  25. {$linklib gpm}
  26. {$linklib c}
  27. {$endif}
  28. {$inline on}
  29. const
  30. _PATH_VARRUN = '/var/run/';
  31. _PATH_DEV = '/dev/';
  32. GPM_NODE_DIR = _PATH_VARRUN;
  33. GPM_NODE_DIR_MODE = 0775;
  34. GPM_NODE_PID = '/var/run/gpm.pid';
  35. GPM_NODE_DEV = '/dev/gpmctl';
  36. GPM_NODE_CTL = GPM_NODE_DEV;
  37. GPM_NODE_FIFO = '/dev/gpmdata';
  38. GPM_B_LEFT = 4;
  39. GPM_B_MIDDLE = 2;
  40. GPM_B_RIGHT = 1;
  41. type
  42. TGpmEtype = longint;
  43. TGpmMargin = longint;
  44. const
  45. GPM_MOVE = 1;
  46. GPM_DRAG = 2;
  47. GPM_DOWN = 4;
  48. GPM_UP = 8;
  49. GPM_SINGLE = 16;
  50. GPM_DOUBLE = 32;
  51. GPM_TRIPLE = 64;
  52. GPM_MFLAG = 128;
  53. GPM_HARD = 256;
  54. GPM_ENTER = 512;
  55. GPM_LEAVE = 1024;
  56. GPM_TOP = 1;
  57. GPM_BOT = 2;
  58. GPM_LFT = 4;
  59. GPM_RGT = 8;
  60. type
  61. {$PACKRECORDS c}
  62. Pgpm_event=^Tgpm_event;
  63. Tgpm_event=record
  64. buttons : byte;
  65. modifiers : byte;
  66. vc : word;
  67. dx : word;
  68. dy : word;
  69. x,y : word;
  70. wdx,wdy : word;
  71. EventType : TGpmEType;
  72. clicks : longint;
  73. margin : TGpmMargin;
  74. end;
  75. Pgpmevent=Pgpm_event;
  76. Tgpmevent=Tgpm_event;
  77. TGpmHandler=function(var event:TGpmEvent;clientdata:pointer):longint;cdecl;
  78. const
  79. GPM_MAGIC = $47706D4C;
  80. type
  81. Pgpm_connect = ^TGpm_connect;
  82. Tgpm_connect = record
  83. eventMask : word;
  84. defaultMask : word;
  85. minMod : word;
  86. maxMod : word;
  87. pid : longint;
  88. vc : longint;
  89. end;
  90. Pgpmconnect=Pgpm_connect;
  91. Tgpmconnect=Tgpm_connect;
  92. Pgpm_roi=^Tgpm_roi;
  93. Tgpm_roi=record
  94. xmin,xmax:integer;
  95. ymin,ymax:integer;
  96. minmod,maxmod:word;
  97. eventmask:word;
  98. owned:word;
  99. handler:Tgpmhandler;
  100. clientdata:pointer;
  101. prev,next:Pgpm_roi;
  102. end;
  103. Pgpmroi=Pgpm_roi;
  104. Tgpmroi=Tgpm_roi;
  105. {$ifdef external}
  106. var
  107. gpm_flag : longint;cvar;external;
  108. gpm_fd : longint;cvar;external;
  109. gpm_hflag : longint;cvar;external;
  110. gpm_morekeys : Longbool;cvar;external;
  111. gpm_zerobased : Longbool;cvar;external;
  112. gpm_visiblepointer : Longbool;cvar;external;
  113. gpm_mx : longint;cvar;external;
  114. gpm_my : longint;cvar;external;
  115. gpm_timeout : TTimeVal;cvar;external;
  116. _gpm_buf : array[0..0] of char;cvar;external;
  117. _gpm_arg : ^word;cvar;external;
  118. gpm_handler : TGpmHandler;cvar;external;
  119. gpm_data : pointer;cvar;external;
  120. gpm_roi_handler : TGpmHandler;cvar;external;
  121. gpm_roi_data : pointer;cvar;external;
  122. gpm_roi : PGpmRoi;cvar;external;
  123. gpm_current_roi : PGpmRoi;cvar;external;
  124. gpm_consolefd : longint;cvar;external;
  125. Gpm_HandleRoi : TGpmHandler;cvar;external;
  126. {$else}
  127. var gpm_roi:Pgpm_roi;
  128. gpm_handler,gpm_roi_handler:Tgpmhandler;
  129. gpm_current_roi:Pgpm_roi;
  130. gpm_roi_data:pointer;
  131. {$endif}
  132. function Gpm_StrictSingle(EventType : longint) : boolean;
  133. function Gpm_AnySingle(EventType : longint) : boolean;
  134. function Gpm_StrictDouble(EventType : longint) : boolean;
  135. function Gpm_AnyDouble(EventType : longint) : boolean;
  136. function Gpm_StrictTriple(EventType : longint) : boolean;
  137. function Gpm_AnyTriple(EventType : longint) : boolean;
  138. {$ifdef use_external}
  139. function Gpm_Open(var _para1:TGpmConnect; _para2:longint):longint;cdecl;external;
  140. function Gpm_Close:longint;cdecl;external;
  141. function Gpm_GetEvent(var _para1:TGpmEvent):longint;cdecl;external;
  142. {function Gpm_Getc(_para1:pFILE):longint;cdecl;external;
  143. function Gpm_Getchar : longint;}
  144. function Gpm_Repeat(millisec:longint):longint;cdecl;external;
  145. function Gpm_FitValuesM(var x,y:longint; margin:longint):longint;cdecl;external;
  146. function Gpm_FitValues(var x,y:longint):longint;cdecl;external;
  147. {function GPM_DRAWPOINTER(ePtr : longint) : longint;}
  148. function Gpm_PushRoi(x1:longint; y1:longint; X2:longint; Y2:longint; mask:longint; fun:TGpmHandler; xtradata:pointer):PGpmRoi;cdecl;external;
  149. function Gpm_PopRoi(which:PGpmRoi):PGpmRoi;cdecl;external;
  150. function Gpm_RaiseRoi(which:PGpmRoi; before:PGpmRoi):PGpmRoi;cdecl;external;
  151. function Gpm_LowerRoi(which:PGpmRoi; after:PGpmRoi):PGpmRoi;cdecl;external;
  152. {function Gpm_Wgetch:longint;cdecl;external;
  153. function Gpm_Getch:longint;}
  154. function Gpm_GetLibVersion(var where:longint):pchar;cdecl;external;
  155. function Gpm_GetServerVersion(var where:longint):pchar;cdecl;external;
  156. function Gpm_GetSnapshot(var ePtr:TGpmEvent):longint;cdecl;external;
  157. {$else}
  158. function gpm_open(var conn:Tgpm_connect;flag:longint):longint;
  159. function gpm_close:longint;
  160. function gpm_getevent(var event:Tgpm_event):longint;
  161. {function Gpm_Getc(_para1:pFILE):longint;cdecl;external;
  162. function Gpm_Getchar : longint;}
  163. function gpm_repeat(millisec:longint):longint;
  164. function gpm_fitvaluesM(var x,y:longint; margin:longint):longint;
  165. function gpm_fitvalues(var x,y:longint):longint;{$ifndef VER1_0}inline;{$endif}
  166. function gpm_pushroi(x1:longint;y1:longint;x2:longint;y2:longint;
  167. mask:longint;fun:Tgpmhandler;xtradata:pointer):Pgpm_roi;
  168. function gpm_poproi(which:Pgpm_roi):Pgpm_roi;
  169. function gpm_raiseroi(which:Pgpm_roi;before:Pgpm_roi):Pgpm_roi;
  170. function gpm_lowerroi(which:Pgpm_roi;after:Pgpm_roi):Pgpm_roi;
  171. {Should be pointer because proc accepts nil.}
  172. function gpm_getsnapshot(eptr:Pgpmevent):longint;
  173. {Overload for compatibility.}
  174. function gpm_getsnapshot(var eptr:Tgpmevent):longint;
  175. {$ifndef VER1_0}inline;{$endif}
  176. {$endif}
  177. {*****************************************************************************}
  178. implementation
  179. {*****************************************************************************}
  180. {$ifndef use_external}
  181. uses termio,sockets,strings,unix;
  182. type Pgpm_stst=^Tgpm_stst;
  183. Tgpm_stst=record
  184. info:Tgpmconnect;
  185. next:Pgpm_stst;
  186. end;
  187. Pmicetab=^Tmicetab;
  188. Tmicetab=record
  189. next:Pmicetab;
  190. device,protocol,options:Pchar;
  191. end;
  192. string63=string[63];
  193. Toptions=record
  194. autodetect:longint;
  195. mice_count:longint;
  196. repeater:longint;
  197. repeater_type:Pchar;
  198. run_status:longint;
  199. micelist:Pmicetab;
  200. progname,
  201. consolename:string63;
  202. end;
  203. var options:Toptions;
  204. gpm_stack:Pgpm_stst;
  205. gpm_mx,gpm_my:longint;
  206. gpm_saved_winch_hook,gpm_saved_suspend_hook:sigactionrec;
  207. const gpm_flag:boolean=false; {almost unuseful now -- where was it used for ? can
  208. we remove it now ? FIXME}
  209. gpm_tried:boolean=false;
  210. gpm_hflag:boolean=false;
  211. gpm_fd:longint=-1;
  212. gpm_consolefd:longint=-1;
  213. gpm_zerobased:longint=0;
  214. const GPM_DEVFS_CONSOLE='/dev/vc/0';
  215. GPM_OLD_CONSOLE='/dev/tty0';
  216. GPM_REQ_SNAPSHOT=0;
  217. GPM_REQ_BUTTONS=1;
  218. GPM_REQ_CONFIG=2;
  219. GPM_REQ_NOPASTE=3;
  220. {$endif}
  221. function Gpm_StrictSingle(EventType : longint) : boolean;
  222. begin
  223. Gpm_StrictSingle:=(EventType and GPM_SINGLE<>0) and not(EventType and GPM_MFLAG<>0);
  224. end;
  225. function Gpm_AnySingle(EventType : longint) : boolean;
  226. begin
  227. Gpm_AnySingle:=(EventType and GPM_SINGLE<>0);
  228. end;
  229. function Gpm_StrictDouble(EventType : longint) : boolean;
  230. begin
  231. Gpm_StrictDouble:=(EventType and GPM_DOUBLE<>0) and not(EventType and GPM_MFLAG<>0);
  232. end;
  233. function Gpm_AnyDouble(EventType : longint) : boolean;
  234. begin
  235. Gpm_AnyDouble:=(EventType and GPM_DOUBLE<>0);
  236. end;
  237. function Gpm_StrictTriple(EventType : longint) : boolean;
  238. begin
  239. Gpm_StrictTriple:=(EventType and GPM_TRIPLE<>0) and not(EventType and GPM_MFLAG<>0);
  240. end;
  241. function Gpm_AnyTriple(EventType : longint) : boolean;
  242. begin
  243. Gpm_AnyTriple:=(EventType and GPM_TRIPLE<>0);
  244. end;
  245. {$ifdef use_external}
  246. procedure Gpm_CheckVersion;
  247. var
  248. l : longint;
  249. begin
  250. Gpm_GetLibVersion(l);
  251. if l<11700 then
  252. begin
  253. writeln('You need at least gpm 1.17');
  254. halt(1);
  255. end;
  256. end;
  257. {$else}
  258. const checked_con:boolean=false;
  259. function putdata(where:longint;const what:Tgpmconnect):boolean;
  260. begin
  261. putdata:=true;
  262. if fpwrite(where,what,sizeof(Tgpmconnect))<>sizeof(Tgpmconnect) then
  263. begin
  264. { gpm_report(GPM_PR_ERR,GPM_MESS_WRITE_ERR,strerror(errno));}
  265. putdata:=false;
  266. end;
  267. end;
  268. function gpm_get_console:string63;
  269. var buf:stat;
  270. begin
  271. {First try the devfs device, because in the next time this will be
  272. the preferred one. If that fails, take the old console.}
  273. {Check for open new console.}
  274. if fpstat(GPM_DEVFS_CONSOLE,buf)=0 then
  275. gpm_get_console:=GPM_DEVFS_CONSOLE
  276. {Failed, try OLD console.}
  277. else if fpstat(GPM_OLD_CONSOLE,buf)=0 then
  278. gpm_get_console:=GPM_OLD_CONSOLE
  279. else
  280. gpm_get_console:='';
  281. end;
  282. procedure gpm_winch_hook(signum:longint);cdecl;
  283. var win:winsize;
  284. begin
  285. if (signalhandler(SIG_IGN)<>gpm_saved_winch_hook.sa_handler) and
  286. (signalhandler(SIG_DFL)<>gpm_saved_winch_hook.sa_handler) then
  287. gpm_saved_winch_hook.sa_handler(signum);
  288. if fpioctl(gpm_consolefd,TIOCGWINSZ,@win)=-1 then
  289. exit;
  290. if (win.ws_col=0) or (win.ws_row=0) then
  291. begin
  292. win.ws_col:=80;
  293. win.ws_row:=25;
  294. end;
  295. gpm_mx:=win.ws_col - gpm_zerobased;
  296. gpm_my:=win.ws_row - gpm_zerobased;
  297. end;
  298. procedure gpm_suspend_hook(signum:longint);cdecl;
  299. var conn:Tgpmconnect;
  300. old_sigset,new_sigset:Tsigset;
  301. sa:sigactionrec;
  302. success:boolean;
  303. begin
  304. fpsigemptyset(new_sigset);
  305. fpsigaddset(new_sigset,SIGTSTP);
  306. fpsigprocmask(SIG_BLOCK,new_sigset,old_sigset);
  307. {Open a completely transparent gpm connection.}
  308. conn.eventmask:=0;
  309. conn.defaultMask:=$ffff;
  310. conn.minmod:=$ffff;
  311. conn.maxmod:=0;
  312. {cannot do this under xterm, tough}
  313. success:=gpm_open(conn,0)>=0;
  314. {take the default action, whatever it is (probably a stop :)}
  315. fpsigprocmask(SIG_SETMASK,@old_sigset,nil);
  316. fpsigaction(SIGTSTP,@gpm_saved_suspend_hook,nil);
  317. fpkill(fpgetpid,SIGTSTP);
  318. { in bardo here }
  319. { Reincarnation. Prepare for another death early. }
  320. fpsigemptyset(sa.sa_mask);
  321. sa.sa_handler:=@gpm_suspend_hook;
  322. sa.sa_flags:=SA_NOMASK;
  323. fpsigaction(SIGTSTP,@sa,nil);
  324. { Pop the gpm stack by closing the useless connection }
  325. { but do it only when we know we opened one.. }
  326. if success then
  327. gpm_close;
  328. end;
  329. function gpm_open(var conn:Tgpmconnect;flag:longint):longint;
  330. var tty:string;
  331. flagstr:string[10];
  332. term:Pchar;
  333. i:cardinal;
  334. addr:Tunixsockaddr;
  335. win:Twinsize;
  336. n:Pgpm_stst;
  337. l:byte;
  338. p:byte; {there max 256 console ttys}
  339. buf:stat;
  340. sa:sigactionrec;
  341. label err;
  342. begin
  343. tty:='';
  344. options.consolename:='';
  345. { gpm_report(GPM_PR_DEBUG,"VC: %d",flag);}
  346. {....................................... First of all, check xterm}
  347. term:=fpgetenv('TERM');
  348. if (term<>nil) and (strcomp(term,'xterm')=0) then
  349. begin
  350. if gpm_tried then
  351. begin
  352. gpm_open:=gpm_fd; { no stack }
  353. exit;
  354. end;
  355. gpm_fd:=-2;
  356. {save old hilit tracking and enable mouse tracking}
  357. write(#27'[?1001s'#27'[?1000h');
  358. flush(output);
  359. gpm_flag:=true;
  360. gpm_open:=gpm_fd;
  361. exit;
  362. end;
  363. {....................................... No xterm, go on}
  364. { check whether we know what name the console is: what's with the lib??? }
  365. if not checked_con then
  366. begin
  367. options.consolename:=gpm_get_console;
  368. checked_con:=true;
  369. end;
  370. { So I chose to use the current tty, instead of /dev/console, which
  371. has permission problems. (I am fool, and my console is
  372. readable/writeable by everybody.
  373. However, making this piece of code work has been a real hassle.}
  374. if not gpm_flag and gpm_tried then
  375. begin
  376. gpm_open:=-1;
  377. exit;
  378. end;
  379. gpm_tried:=true; {do or die}
  380. new(n);
  381. n^.next:=gpm_stack;
  382. gpm_stack:=n;
  383. conn.pid:=fpgetpid; { fill obvious values }
  384. if n^.next<>nil then
  385. conn.vc:=n^.next^.info.vc {inherit}
  386. else
  387. begin
  388. conn.vc:=0; { default handler }
  389. if (flag>0) then
  390. begin { forced vc number }
  391. conn.vc:=flag;
  392. str(flag,flagstr);
  393. tty:=options.consolename+flagstr;
  394. end
  395. else
  396. begin {use your current vc}
  397. if isatty(0)<>0 then
  398. tty:=ttyname(0); { stdin }
  399. if (tty='') and (isatty(1)<>0) then
  400. tty:=ttyname(1); { stdout }
  401. if (tty='') and (isatty(2)<>0) then
  402. tty:=ttyname(2); { stderr }
  403. if (tty='') then
  404. begin
  405. { gpm_report(GPM_PR_ERR,"checking tty name failed");}
  406. goto err;
  407. end;
  408. conn.vc:=0;
  409. l:=length(tty);
  410. p:=1;
  411. while tty[l] in ['0'..'9'] do
  412. begin
  413. inc(conn.vc,p*(byte(tty[l])-byte('0')));
  414. p:=p*10;
  415. dec(l);
  416. end;
  417. end;
  418. if (gpm_consolefd=-1) then
  419. begin
  420. gpm_consolefd:=fpopen(tty,O_WRONLY);
  421. if gpm_consolefd<0 then
  422. begin
  423. { gpm_report(GPM_PR_ERR,GPM_MESS_DOUBLE_S,tty,strerror(errno));}
  424. goto err;
  425. end;
  426. end;
  427. end;
  428. n^.info:=conn;
  429. {....................................... Get screen dimensions }
  430. fpioctl(gpm_consolefd, TIOCGWINSZ, @win);
  431. if (win.ws_col or win.ws_row)=0 then
  432. begin
  433. {Hmmmm. The mad terminal didn't return it's size :/ }
  434. { fprintf(stderr, "libgpm: zero screen dimension, assuming 80x25.\n");}
  435. win.ws_col:=80;
  436. win.ws_row:=25;
  437. end;
  438. gpm_mx:=win.ws_col-gpm_zerobased;
  439. gpm_my:=win.ws_row-gpm_zerobased;
  440. {....................................... Connect to the control socket}
  441. if not gpm_flag then
  442. begin
  443. gpm_fd:=socket(AF_UNIX,SOCK_STREAM,0);
  444. if gpm_fd<0 then
  445. begin
  446. { gpm_report(GPM_PR_ERR,GPM_MESS_SOCKET,strerror(errno));}
  447. goto err;
  448. end;
  449. end;
  450. fillchar(addr,sizeof(addr),0);
  451. addr.family:=PF_UNIX;
  452. strcopy(addr.path, GPM_NODE_CTL);
  453. i:=sizeof(addr.family)+length(GPM_NODE_CTL);
  454. if fpconnect(gpm_fd,@addr,i)<0 then
  455. begin
  456. { gpm_report(GPM_PR_INFO,GPM_MESS_DOUBLE_S,GPM_NODE_CTL,strerror(errno));}
  457. {Well, try to open a chr device called /dev/gpmctl. This should
  458. be forward-compatible with a kernel server.}
  459. fpclose(gpm_fd); {the socket}
  460. gpm_fd:=fpopen(GPM_NODE_DEV,O_RDWR);
  461. if gpm_fd=-1 then
  462. begin
  463. { gpm_report(GPM_PR_ERR,GPM_MESS_DOUBLE_S,GPM_NODE_DEV
  464. ,strerror(errno));}
  465. goto err;
  466. end;
  467. if (fpfstat(gpm_fd,buf)=-1) or (buf.st_mode and STAT_IFMT<>STAT_IFCHR) then
  468. goto err;
  469. end;
  470. {....................................... Put your data}
  471. if putdata(gpm_fd,conn) then
  472. begin
  473. { itz Wed Dec 16 23:22:16 PST 1998 use sigaction, the old
  474. code caused a signal loop under XEmacs }
  475. fpsigemptyset(sa.sa_mask);
  476. { And the winch (window-resize) hook .. }
  477. sa.sa_handler:=@gpm_winch_hook;
  478. sa.sa_flags:=0;
  479. fpsigaction(SIGWINCH,@sa,@gpm_saved_winch_hook);
  480. if gpm_flag then
  481. begin
  482. { Install suspend hook }
  483. sa.sa_handler:=signalhandler(SIG_IGN);
  484. fpsigaction(SIGTSTP,@sa,@gpm_saved_suspend_hook);
  485. {if signal was originally ignored, job control is not supported}
  486. if gpm_saved_suspend_hook.sa_handler<>signalhandler(SIG_IGN) then
  487. begin
  488. sa.sa_flags:=SA_NOMASK;
  489. sa.sa_handler:=@gpm_suspend_hook;
  490. fpsigaction(SIGTSTP,@sa,nil);
  491. end;
  492. end;
  493. end;
  494. gpm_open:=gpm_fd;
  495. exit;
  496. {....................................... Error: free all memory}
  497. err:
  498. { gpm_report(GPM_PR_ERR,'Oh, oh, it''s an error! possibly I die! ');}
  499. repeat
  500. n:=gpm_stack^.next;
  501. dispose(gpm_stack);
  502. gpm_stack:=n;
  503. until gpm_stack=nil;
  504. if gpm_fd>=0 then
  505. fpclose(gpm_fd);
  506. gpm_flag:=false;
  507. gpm_open:=-1;
  508. end;
  509. function gpm_close:longint;
  510. var next:Pgpm_stst;
  511. begin
  512. gpm_tried:=false; { reset the error flag for next time }
  513. if gpm_fd=-2 then { xterm }
  514. begin
  515. write(#27'[?1000l'#27'[?1001r');
  516. flush(output);
  517. end
  518. else { linux }
  519. begin
  520. if not gpm_flag then
  521. gpm_close:=0
  522. else
  523. begin
  524. next:=gpm_stack^.next;
  525. dispose(gpm_stack);
  526. gpm_stack:=next;
  527. if next<>nil then
  528. putdata(gpm_fd,next^.info);
  529. gpm_flag:=false;
  530. end;
  531. end;
  532. if gpm_fd>=0 then
  533. fpclose(gpm_fd);
  534. gpm_fd:=-1;
  535. fpsigaction(SIGTSTP,@gpm_saved_suspend_hook,nil);
  536. fpsigaction(SIGWINCH,@gpm_saved_winch_hook,nil);
  537. fpclose(gpm_consolefd);
  538. gpm_consolefd:=-1;
  539. gpm_close:=0;
  540. end;
  541. function gpm_getevent(var event:Tgpm_event):longint;
  542. var count:longint;
  543. begin
  544. gpm_getevent:=0;
  545. if not gpm_flag then
  546. exit;
  547. count:=fpread(gpm_fd,event,sizeof(Tgpm_event));
  548. if count<>sizeof(Tgpm_event) then
  549. begin
  550. {avoid to send the message if there is no data; sometimes it makes
  551. sense to poll the mouse descriptor any now an then using a
  552. non-blocking descriptor}
  553. { if (count<>-1) or (errno<>EAGAIN)
  554. gpm_report(GPM_PR_INFO,"Read too few bytes (%i) at %s:%d",
  555. count,__FILE__,__LINE__);}
  556. gpm_getevent:=-1;
  557. exit;
  558. end;
  559. dec(event.x,gpm_zerobased);
  560. dec(event.y,gpm_zerobased);
  561. gpm_getevent:=1;
  562. end;
  563. function gpm_repeat(millisec:longint):longint;
  564. var fd:longint;
  565. selset:Tfdset;
  566. begin
  567. fd:=0; {Default to stdin (xterm).}
  568. if gpm_fd>=0 then
  569. fd:=gpm_fd;
  570. fpFD_ZERO(selset);
  571. fpFD_SET(fd,selset);
  572. gpm_repeat:=fpselect(fd+1,@selset,nil,nil,millisec);
  573. end;
  574. function gpm_fitvaluesM(var x,y:longint;margin:longint):longint;
  575. begin
  576. gpm_fitvaluesM:=0;
  577. if margin=-1 then
  578. begin
  579. if x<gpm_zerobased then
  580. x:=gpm_zerobased
  581. else if x>gpm_mx then
  582. x:=gpm_mx;
  583. if y<gpm_zerobased then
  584. y:=gpm_zerobased
  585. else if y>gpm_my then
  586. y:=gpm_my;
  587. end
  588. else
  589. case margin of
  590. GPM_TOP:
  591. inc(y);
  592. GPM_BOT:
  593. dec(y);
  594. GPM_RGT:
  595. dec(x);
  596. GPM_LFT:
  597. inc(x);
  598. end;
  599. end;
  600. function gpm_fitvalues(var x,y:longint):longint;
  601. {$ifndef VER1_0}inline;{$endif}
  602. begin
  603. gpm_fitvalues:=gpm_fitvaluesm(x,y,-1);
  604. end;
  605. function gpm_handle_roi(var eptr:Tgpm_event;clientdata:pointer):longint;cdecl;
  606. var backevent:Tgpm_event;
  607. roi:Pgpm_roi;
  608. begin
  609. roi:=gpm_current_roi;
  610. {If motion or press, look for the interested roi.
  611. Drag and release will be reported to the old roi.}
  612. if eptr.eventtype and (GPM_MOVE or GPM_DOWN)<>0 then
  613. begin
  614. roi:=gpm_roi;
  615. while roi<>nil do
  616. begin
  617. if not ((roi^.xmin>eptr.x) or (roi^.xmax<eptr.x)) and
  618. not ((roi^.ymin>eptr.y) or (roi^.ymax<eptr.y)) and
  619. not ((roi^.minmod and eptr.modifiers)<roi^.minmod) and
  620. not ((roi^.maxmod and eptr.modifiers)<eptr.modifiers) then
  621. break;
  622. roi:=roi^.next;
  623. end;
  624. end;
  625. {Now generate the leave/enter events}
  626. if roi<>gpm_current_roi then
  627. begin
  628. if (gpm_current_roi<>nil) and (gpm_current_roi^.eventmask and GPM_LEAVE<>0) then
  629. begin
  630. backevent.eventtype:=GPM_LEAVE;
  631. gpm_current_roi^.handler(backevent,gpm_current_roi^.clientdata);
  632. end;
  633. if (roi<>nil) and (roi^.eventmask and GPM_ENTER<>0) then
  634. begin
  635. backevent.eventtype:=GPM_ENTER;
  636. roi^.handler(backevent,roi^.clientdata);
  637. end;
  638. end;
  639. gpm_current_roi:=roi;
  640. {events not requested are discarded}
  641. if (roi<>nil) and (eptr.eventtype and ($0f or GPM_ENTER or GPM_LEAVE) and roi^.eventmask=0) then
  642. gpm_handle_roi:=0
  643. else
  644. begin
  645. backevent:=eptr; {copy it, so the main one is unchanged}
  646. if roi=nil then
  647. if gpm_roi_handler<>nil then
  648. gpm_handle_roi:=gpm_roi_handler(backevent,gpm_roi_data)
  649. else
  650. gpm_handle_roi:=0
  651. else
  652. begin
  653. {Ok, now report the event as it is, after modifying x and y}
  654. dec(backevent.x,roi^.xmin);
  655. dec(backevent.y,roi^.ymin);
  656. roi^.handler(backevent,roi^.clientdata);
  657. end;
  658. end;
  659. end;
  660. function gpm_pushroi(x1:longint;y1:longint;x2:longint;y2:longint;
  661. mask:longint;fun:Tgpmhandler;xtradata:pointer):Pgpm_roi;
  662. var n:Pgpm_roi;
  663. begin
  664. {create a roi and push it}
  665. new(n);
  666. {use the roi handler, if still null}
  667. if (gpm_roi<>nil) and (gpm_handler<>nil) then
  668. gpm_handler:=@gpm_handle_roi;
  669. n^.xmin:=x1; n^.xmax:=x2;
  670. n^.ymin:=y1; n^.ymax:=y2;
  671. n^.minmod:=0; n^.maxmod:=$ffff;
  672. n^.prev:=nil; n^.next:=nil;
  673. n^.eventmask:=mask;
  674. n^.owned:=0; { use dispose }
  675. n^.handler:=fun;
  676. if xtradata=nil then
  677. n^.clientdata:=n
  678. else
  679. n^.clientdata:=xtradata;
  680. gpm_pushroi:=gpm_raiseroi(n,nil);
  681. end;
  682. function gpm_useroi(n:Pgpm_roi):Pgpm_roi;
  683. begin
  684. { use a Roi by pushing it }
  685. n^.prev:=nil;
  686. n^.next:=nil;
  687. n^.owned:=1;
  688. { use the roi handler, if still nil }
  689. if (gpm_roi=nil) and (gpm_handler=nil) then
  690. gpm_handler:=@gpm_handle_roi;
  691. gpm_useroi:=gpm_raiseroi(n,nil);
  692. end;
  693. function gpm_poproi(which:Pgpmroi):Pgpmroi;
  694. begin
  695. {extract the Roi and remove it}
  696. if which^.prev<>nil then
  697. which^.prev^.next:=which^.next;
  698. if which^.next<>nil then
  699. which^.next^.prev:=which^.prev;
  700. if gpm_roi=which then
  701. gpm_roi:=which^.next;
  702. if which^.owned=0 then
  703. dispose(which);
  704. if gpm_current_roi=which then
  705. gpm_current_roi:=nil;
  706. gpm_poproi:=gpm_roi; {return the new top-of-stack}
  707. end;
  708. function gpm_raiseroi(which:Pgpmroi;before:Pgpmroi):Pgpmroi;
  709. begin
  710. {raise a Roi above another, or to top-of-stack}
  711. if gpm_roi=nil then
  712. begin
  713. gpm_roi:=which;
  714. gpm_raiseroi:=which;
  715. exit;
  716. end;
  717. if before=nil then
  718. before:=gpm_roi;
  719. if before=which then
  720. begin
  721. gpm_raiseroi:=gpm_roi;
  722. exit;
  723. end;
  724. if which^.prev<>nil then
  725. which^.prev^.next:=which^.next;
  726. if which^.next<>nil then
  727. which^.next^.prev:=which^.prev;
  728. if gpm_roi=which then
  729. gpm_roi:=which^.next;
  730. which^.prev:=before^.prev;
  731. before^.prev:=which;
  732. which^.next:=before;
  733. if which^.prev<>nil then
  734. which^.prev^.next:=which
  735. else
  736. gpm_roi:=which;
  737. gpm_raiseroi:=gpm_roi; { return the new top-of-stack }
  738. end;
  739. function gpm_lowerroi(which:Pgpmroi;after:Pgpmroi):Pgpmroi;
  740. begin
  741. {lower a Roi below another, or to bottom-of-stack}
  742. if after=nil then
  743. begin
  744. after:=gpm_roi;
  745. while after^.next<>nil do
  746. after:=after^.next;
  747. end;
  748. if after=which then
  749. begin
  750. gpm_lowerroi:=gpm_roi;
  751. exit;
  752. end;
  753. if which^.prev<>nil then
  754. which^.prev^.next:=which^.next;
  755. if which^.next<>nil then
  756. which^.next^.prev:=which^.prev;
  757. if gpm_roi=which then
  758. gpm_roi:=which^.next;
  759. which^.next:=after^.next;
  760. after^.next:=which;
  761. which^.prev:=after;
  762. if which^.next<>nil then
  763. which^.next^.prev:=which;
  764. gpm_lowerroi:=gpm_roi; {return the new top-of-stack}
  765. end;
  766. function gpm_getsnapshot(eptr:Pgpm_event):longint;
  767. var conn:Tgpm_connect;
  768. event:Tgpm_event;
  769. sillyset:Tfdset;
  770. i:longint;
  771. begin
  772. conn.pid:=0; { this signals a request }
  773. if eptr<>nil then
  774. conn.vc:=GPM_REQ_SNAPSHOT
  775. else
  776. begin
  777. conn.vc:=GPM_REQ_BUTTONS;
  778. eptr:=@event;
  779. end;
  780. if gpm_fd=-1 then
  781. begin
  782. gpm_getsnapshot:=-1;
  783. exit;
  784. end;
  785. fpFD_ZERO(sillyset);
  786. fpFD_SET(gpm_fd,sillyset);
  787. if fpselect(gpm_fd+1,@sillyset,nil,nil,0)=1 then
  788. gpm_getsnapshot:=0
  789. else
  790. begin
  791. fpwrite(gpm_fd,conn,sizeof(Tgpm_connect));
  792. i:=gpm_getevent(eptr^);
  793. if i<>1 then
  794. gpm_getsnapshot:=-1
  795. else
  796. begin
  797. gpm_getsnapshot:=eptr^.eventtype; { number of buttons }
  798. eptr^.eventtype:=0;
  799. end;
  800. end;
  801. end;
  802. function gpm_getsnapshot(var eptr:Tgpmevent):longint;
  803. {$ifndef VER1_0}inline;{$endif}
  804. begin
  805. gpm_getsnapshot:=gpm_getsnapshot(@eptr);
  806. end;
  807. {$endif}
  808. end.
  809. {
  810. $Log$
  811. Revision 1.11 2004-11-02 09:37:35 peter
  812. * fixed uninitialzied local
  813. Revision 1.10 2004/07/09 23:10:14 peter
  814. * fixed range check errors
  815. Revision 1.9 2004/07/09 22:40:02 daniel
  816. * Fixed fitvalues
  817. Revision 1.8 2004/07/09 19:03:35 peter
  818. * isatty return cint again
  819. Revision 1.7 2004/07/08 13:23:21 daniel
  820. * gpm now uses a Pascal translation of libgpm instead of linking against
  821. it.
  822. * isatty result type changed into boolean
  823. Revision 1.6 2003/09/14 20:15:01 marco
  824. * Unix reform stage two. Remove all calls from Unix that exist in Baseunix.
  825. Revision 1.5 2002/09/07 16:01:27 peter
  826. * old logs removed and tabs fixed
  827. }