gpm.pp 26 KB

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