gpm.pp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 1999-2000 by Peter Vreman
  4. GPM (>v1.17) mouse Interface for linux
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY;without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. unit gpm;
  12. {Note: Libgpm is *the* interface for Linux text-mode programs.
  13. Unfortunately it isn't suitable for anything else besides a blocky
  14. cursor on a text mode interface. The GPM protocol suffers from serious
  15. defficiencies and ideally, gpm is abolished as quickly as possible.
  16. With lack of a good alternative, GPM deserves good support. But
  17. please keep this in mind while coding.}
  18. {*****************************************************************************}
  19. interface
  20. {*****************************************************************************}
  21. uses
  22. baseUnix;
  23. {$ifdef use_external}
  24. {$linklib gpm}
  25. {$linklib c}
  26. {$endif}
  27. {$inline on}
  28. {$goto 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=packed record
  64. buttons : byte;
  65. modifiers : byte;
  66. vc : word;
  67. dx : word;
  68. dy : word;
  69. x,y : word;
  70. EventType : TGpmEType;
  71. clicks : longint;
  72. margin : TGpmMargin;
  73. wdx,wdy : word;
  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 = packed 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=packed 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 name 'Gpm_Open';
  140. function Gpm_Close:longint;cdecl;external name 'Gpm_Close';
  141. function Gpm_GetEvent(var _para1:TGpmEvent):longint;cdecl;external name 'Gpm_GetEvent';
  142. {function Gpm_Getc(_para1:pFILE):longint;cdecl;external;
  143. function Gpm_Getchar : longint;}
  144. function Gpm_Repeat(millisec:longint):longint;cdecl;external name 'Gpm_Repeat';
  145. function Gpm_FitValuesM(var x,y:longint; margin:longint):longint;cdecl;external name 'Gpm_FitValuesM';
  146. function Gpm_FitValues(var x,y:longint):longint;cdecl;external name 'Gpm_FitValues';
  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 name 'Gpm_PushRoi';
  149. function Gpm_PopRoi(which:PGpmRoi):PGpmRoi;cdecl;external name 'Gpm_PopRoi';
  150. function Gpm_RaiseRoi(which:PGpmRoi; before:PGpmRoi):PGpmRoi;cdecl;external name 'Gpm_RaiseRoi';
  151. function Gpm_LowerRoi(which:PGpmRoi; after:PGpmRoi):PGpmRoi;cdecl;external name 'Gpm_LowerRoi';
  152. {function Gpm_Wgetch:longint;cdecl;external;
  153. function Gpm_Getch:longint;}
  154. function Gpm_GetLibVersion(var where:longint):pchar;cdecl;external name 'Gpm_GetLibVersion';
  155. function Gpm_GetServerVersion(var where:longint):pchar;cdecl;external name 'Gpm_GetServerVersion';
  156. function gpm_getsnapshot(eptr:Pgpmevent):longint;cdecl;external name 'Gpm_GetSnapshot';
  157. function Gpm_GetSnapshot(var ePtr:TGpmEvent):longint;cdecl;external name 'Gpm_GetSnapshot';
  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;inline;
  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;inline;
  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. var
  261. res: cint;
  262. begin
  263. putdata:=true;
  264. repeat
  265. res:=fpwrite(where,what,sizeof(Tgpmconnect));
  266. until (res<>-1) or (fpgeterrno<>ESysEINTR);
  267. if res<>sizeof(Tgpmconnect) then
  268. begin
  269. { gpm_report(GPM_PR_ERR,GPM_MESS_WRITE_ERR,strerror(errno));}
  270. putdata:=false;
  271. end;
  272. end;
  273. function gpm_get_console:string63;
  274. var buf:stat;
  275. begin
  276. {First try the devfs device, because in the next time this will be
  277. the preferred one. If that fails, take the old console.}
  278. {Check for open new console.}
  279. if fpstat(GPM_DEVFS_CONSOLE,buf)=0 then
  280. gpm_get_console:=GPM_DEVFS_CONSOLE
  281. {Failed, try OLD console.}
  282. else if fpstat(GPM_OLD_CONSOLE,buf)=0 then
  283. gpm_get_console:=GPM_OLD_CONSOLE
  284. else
  285. gpm_get_console:='';
  286. end;
  287. procedure gpm_winch_hook(signum:longint;SigInfo: PSigInfo; SigContext: PSigContext);cdecl;
  288. var win:winsize;
  289. begin
  290. if (sigactionhandler(SIG_IGN)<>gpm_saved_winch_hook.sa_handler) and
  291. (sigactionhandler(SIG_DFL)<>gpm_saved_winch_hook.sa_handler) then
  292. gpm_saved_winch_hook.sa_handler(signum,nil,nil);
  293. if fpioctl(gpm_consolefd,TIOCGWINSZ,@win)=-1 then
  294. exit;
  295. if (win.ws_col=0) or (win.ws_row=0) then
  296. begin
  297. win.ws_col:=80;
  298. win.ws_row:=25;
  299. end;
  300. gpm_mx:=win.ws_col - gpm_zerobased;
  301. gpm_my:=win.ws_row - gpm_zerobased;
  302. end;
  303. procedure gpm_suspend_hook(signum:longint;SigInfo: PSigInfo; SigContext: PSigContext);cdecl;
  304. var conn:Tgpmconnect;
  305. old_sigset,new_sigset:Tsigset;
  306. sa:sigactionrec;
  307. success:boolean;
  308. begin
  309. fpsigemptyset(new_sigset);
  310. fpsigaddset(new_sigset,SIGTSTP);
  311. fpsigprocmask(SIG_BLOCK,new_sigset,old_sigset);
  312. {Open a completely transparent gpm connection.}
  313. conn.eventmask:=0;
  314. conn.defaultMask:=$ffff;
  315. conn.minmod:=$ffff;
  316. conn.maxmod:=0;
  317. {cannot do this under xterm, tough}
  318. success:=gpm_open(conn,0)>=0;
  319. {take the default action, whatever it is (probably a stop :)}
  320. fpsigprocmask(SIG_SETMASK,@old_sigset,nil);
  321. fpsigaction(SIGTSTP,@gpm_saved_suspend_hook,nil);
  322. fpkill(fpgetpid,SIGTSTP);
  323. { in bardo here }
  324. { Reincarnation. Prepare for another death early. }
  325. fpsigemptyset(sa.sa_mask);
  326. sa.sa_handler:=@gpm_suspend_hook;
  327. sa.sa_flags:=SA_NOMASK;
  328. fpsigaction(SIGTSTP,@sa,nil);
  329. { Pop the gpm stack by closing the useless connection }
  330. { but do it only when we know we opened one.. }
  331. if success then
  332. gpm_close;
  333. end;
  334. function gpm_open(var conn:Tgpmconnect;flag:longint):longint;
  335. var tty:string;
  336. flagstr:string[10];
  337. term:Pchar;
  338. i:cardinal;
  339. addr:Tunixsockaddr;
  340. win:Twinsize;
  341. n:Pgpm_stst;
  342. l:byte;
  343. p:byte; {there max 256 console ttys}
  344. buf:stat;
  345. sa:sigactionrec;
  346. res: cint;
  347. label err;
  348. begin
  349. tty:='';
  350. options.consolename:='';
  351. { gpm_report(GPM_PR_DEBUG,"VC: %d",flag);}
  352. {....................................... First of all, check xterm}
  353. (*
  354. term:=fpgetenv('TERM');
  355. if (term<>nil) and (strcomp(term,'xterm')=0) then
  356. begin
  357. if gpm_tried then
  358. begin
  359. gpm_open:=gpm_fd; { no stack }
  360. exit;
  361. end;
  362. gpm_fd:=-2;
  363. {save old hilit tracking and enable mouse tracking}
  364. write(#27'[?1001s'#27'[?1000h');
  365. flush(output);
  366. gpm_flag:=true;
  367. gpm_open:=gpm_fd;
  368. exit;
  369. end;
  370. *)
  371. {....................................... No xterm, go on}
  372. { check whether we know what name the console is: what's with the lib??? }
  373. if not checked_con then
  374. begin
  375. options.consolename:=gpm_get_console;
  376. checked_con:=true;
  377. end;
  378. { So I chose to use the current tty, instead of /dev/console, which
  379. has permission problems. (I am fool, and my console is
  380. readable/writeable by everybody.
  381. However, making this piece of code work has been a real hassle.}
  382. if not gpm_flag and gpm_tried then
  383. begin
  384. gpm_open:=-1;
  385. exit;
  386. end;
  387. gpm_tried:=true; {do or die}
  388. new(n);
  389. n^.next:=gpm_stack;
  390. gpm_stack:=n;
  391. conn.pid:=fpgetpid; { fill obvious values }
  392. if n^.next<>nil then
  393. conn.vc:=n^.next^.info.vc {inherit}
  394. else
  395. begin
  396. conn.vc:=0; { default handler }
  397. if (flag>0) then
  398. begin { forced vc number }
  399. conn.vc:=flag;
  400. str(flag,flagstr);
  401. tty:=options.consolename+flagstr;
  402. end
  403. else
  404. begin {use your current vc}
  405. if isatty(0)<>0 then
  406. tty:=ttyname(0); { stdin }
  407. if (tty='') and (isatty(1)<>0) then
  408. tty:=ttyname(1); { stdout }
  409. if (tty='') and (isatty(2)<>0) then
  410. tty:=ttyname(2); { stderr }
  411. if (tty='') then
  412. begin
  413. { gpm_report(GPM_PR_ERR,"checking tty name failed");}
  414. goto err;
  415. end;
  416. conn.vc:=0;
  417. l:=length(tty);
  418. p:=1;
  419. while tty[l] in ['0'..'9'] do
  420. begin
  421. inc(conn.vc,p*(byte(tty[l])-byte('0')));
  422. p:=p*10;
  423. dec(l);
  424. end;
  425. end;
  426. if (gpm_consolefd=-1) then
  427. begin
  428. repeat
  429. gpm_consolefd:=fpopen(tty,O_WRONLY);
  430. until (gpm_consolefd<>-1) or (fpgeterrno<>ESysEINTR);
  431. if gpm_consolefd<0 then
  432. begin
  433. { gpm_report(GPM_PR_ERR,GPM_MESS_DOUBLE_S,tty,strerror(errno));}
  434. goto err;
  435. end;
  436. end;
  437. end;
  438. n^.info:=conn;
  439. {....................................... Get screen dimensions }
  440. fpioctl(gpm_consolefd, TIOCGWINSZ, @win);
  441. if (win.ws_col or win.ws_row)=0 then
  442. begin
  443. {Hmmmm. The mad terminal didn't return it's size :/ }
  444. { fprintf(stderr, "libgpm: zero screen dimension, assuming 80x25.\n");}
  445. win.ws_col:=80;
  446. win.ws_row:=25;
  447. end;
  448. gpm_mx:=win.ws_col-gpm_zerobased;
  449. gpm_my:=win.ws_row-gpm_zerobased;
  450. {....................................... Connect to the control socket}
  451. if not gpm_flag then
  452. begin
  453. gpm_fd:=fpsocket(AF_UNIX,SOCK_STREAM,0);
  454. if gpm_fd<0 then
  455. begin
  456. { gpm_report(GPM_PR_ERR,GPM_MESS_SOCKET,strerror(errno));}
  457. goto err;
  458. end;
  459. end;
  460. fillchar(addr,sizeof(addr),0);
  461. addr.family:=PF_UNIX;
  462. strcopy(addr.path, GPM_NODE_CTL);
  463. i:=sizeof(addr.family)+length(GPM_NODE_CTL);
  464. repeat
  465. res:=fpconnect(gpm_fd,psockaddr(@addr),i);
  466. until (res<>-1) or (fpgeterrno<>ESysEINTR);
  467. if res<0 then
  468. begin
  469. { gpm_report(GPM_PR_INFO,GPM_MESS_DOUBLE_S,GPM_NODE_CTL,strerror(errno));}
  470. {Well, try to open a chr device called /dev/gpmctl. This should
  471. be forward-compatible with a kernel server.}
  472. repeat
  473. res:=fpclose(gpm_fd); {the socket}
  474. until (res<>-1) or (fpgeterrno<>ESysEINTR);
  475. repeat
  476. gpm_fd:=fpopen(GPM_NODE_DEV,O_RDWR);
  477. until (gpm_fd<>-1) or (fpgeterrno<>ESysEINTR);
  478. if gpm_fd=-1 then
  479. begin
  480. { gpm_report(GPM_PR_ERR,GPM_MESS_DOUBLE_S,GPM_NODE_DEV
  481. ,strerror(errno));}
  482. goto err;
  483. end;
  484. if (fpfstat(gpm_fd,buf)=-1) or (buf.st_mode and STAT_IFMT<>STAT_IFCHR) then
  485. goto err;
  486. end;
  487. {....................................... Put your data}
  488. if putdata(gpm_fd,conn) then
  489. begin
  490. { itz Wed Dec 16 23:22:16 PST 1998 use sigaction, the old
  491. code caused a signal loop under XEmacs }
  492. fpsigemptyset(sa.sa_mask);
  493. { And the winch (window-resize) hook .. }
  494. sa.sa_handler:=@gpm_winch_hook;
  495. sa.sa_flags:=0;
  496. fpsigaction(SIGWINCH,@sa,@gpm_saved_winch_hook);
  497. if gpm_flag then
  498. begin
  499. { Install suspend hook }
  500. sa.sa_handler:=sigactionhandler(SIG_IGN);
  501. fpsigaction(SIGTSTP,@sa,@gpm_saved_suspend_hook);
  502. {if signal was originally ignored, job control is not supported}
  503. if gpm_saved_suspend_hook.sa_handler<>sigactionhandler(SIG_IGN) then
  504. begin
  505. sa.sa_flags:=SA_NOMASK;
  506. sa.sa_handler:=@gpm_suspend_hook;
  507. fpsigaction(SIGTSTP,@sa,nil);
  508. end;
  509. end;
  510. end;
  511. gpm_open:=gpm_fd;
  512. exit;
  513. {....................................... Error: free all memory}
  514. err:
  515. { gpm_report(GPM_PR_ERR,'Oh, oh, it''s an error! possibly I die! ');}
  516. repeat
  517. n:=gpm_stack^.next;
  518. dispose(gpm_stack);
  519. gpm_stack:=n;
  520. until gpm_stack=nil;
  521. if gpm_fd>=0 then
  522. begin
  523. repeat
  524. res:=fpclose(gpm_fd);
  525. until (res<>-1) or (fpgeterrno<>ESysEINTR);
  526. end;
  527. gpm_flag:=false;
  528. gpm_open:=-1;
  529. end;
  530. function gpm_close:longint;
  531. var
  532. next:Pgpm_stst;
  533. res: cint;
  534. begin
  535. gpm_tried:=false; { reset the error flag for next time }
  536. (*
  537. if gpm_fd=-2 then { xterm }
  538. begin
  539. write(#27'[?1000l'#27'[?1001r');
  540. flush(output);
  541. end
  542. else { linux }
  543. *)
  544. begin
  545. if not gpm_flag then
  546. gpm_close:=0
  547. else
  548. begin
  549. next:=gpm_stack^.next;
  550. dispose(gpm_stack);
  551. gpm_stack:=next;
  552. if next<>nil then
  553. putdata(gpm_fd,next^.info);
  554. gpm_flag:=false;
  555. end;
  556. end;
  557. if gpm_fd>=0 then
  558. begin
  559. repeat
  560. res:=fpclose(gpm_fd);
  561. until (res<>-1) or (fpgeterrno<>ESysEINTR);
  562. end;
  563. gpm_fd:=-1;
  564. fpsigaction(SIGTSTP,@gpm_saved_suspend_hook,nil);
  565. fpsigaction(SIGWINCH,@gpm_saved_winch_hook,nil);
  566. fpclose(gpm_consolefd);
  567. gpm_consolefd:=-1;
  568. gpm_close:=0;
  569. end;
  570. function gpm_getevent(var event:Tgpm_event):longint;
  571. var count:cint;
  572. begin
  573. gpm_getevent:=0;
  574. if gpm_fd=-1 then
  575. exit;
  576. repeat
  577. count:=fpread(gpm_fd,event,sizeof(Tgpm_event));
  578. until (count<>-1) or (fpgeterrno<>ESysEINTR);
  579. if count<>sizeof(Tgpm_event) then
  580. begin
  581. {avoid to send the message if there is no data; sometimes it makes
  582. sense to poll the mouse descriptor any now an then using a
  583. non-blocking descriptor}
  584. { if (count<>-1) or (errno<>EAGAIN)
  585. gpm_report(GPM_PR_INFO,"Read too few bytes (%i) at %s:%d",
  586. count,__FILE__,__LINE__);}
  587. gpm_getevent:=-1;
  588. exit;
  589. end;
  590. dec(event.x,gpm_zerobased);
  591. dec(event.y,gpm_zerobased);
  592. gpm_getevent:=1;
  593. end;
  594. function gpm_repeat(millisec:longint):longint;
  595. var fd:longint;
  596. selset:Tfdset;
  597. begin
  598. fd:=0; {Default to stdin (xterm).}
  599. if gpm_fd>=0 then
  600. fd:=gpm_fd;
  601. fpFD_ZERO(selset);
  602. fpFD_SET(fd,selset);
  603. gpm_repeat:=fpselect(fd+1,@selset,nil,nil,millisec);
  604. end;
  605. function gpm_fitvaluesM(var x,y:longint;margin:longint):longint;
  606. begin
  607. gpm_fitvaluesM:=0;
  608. if margin=-1 then
  609. begin
  610. if x<gpm_zerobased then
  611. x:=gpm_zerobased
  612. else if x>gpm_mx then
  613. x:=gpm_mx;
  614. if y<gpm_zerobased then
  615. y:=gpm_zerobased
  616. else if y>gpm_my then
  617. y:=gpm_my;
  618. end
  619. else
  620. case margin of
  621. GPM_TOP:
  622. inc(y);
  623. GPM_BOT:
  624. dec(y);
  625. GPM_RGT:
  626. dec(x);
  627. GPM_LFT:
  628. inc(x);
  629. end;
  630. end;
  631. function gpm_fitvalues(var x,y:longint):longint;inline;
  632. begin
  633. gpm_fitvalues:=gpm_fitvaluesm(x,y,-1);
  634. end;
  635. function gpm_handle_roi(var eptr:Tgpm_event;clientdata:pointer):longint;cdecl;
  636. var backevent:Tgpm_event;
  637. roi:Pgpm_roi;
  638. begin
  639. roi:=gpm_current_roi;
  640. {If motion or press, look for the interested roi.
  641. Drag and release will be reported to the old roi.}
  642. if eptr.eventtype and (GPM_MOVE or GPM_DOWN)<>0 then
  643. begin
  644. roi:=gpm_roi;
  645. while roi<>nil do
  646. begin
  647. if not ((roi^.xmin>eptr.x) or (roi^.xmax<eptr.x)) and
  648. not ((roi^.ymin>eptr.y) or (roi^.ymax<eptr.y)) and
  649. not ((roi^.minmod and eptr.modifiers)<roi^.minmod) and
  650. not ((roi^.maxmod and eptr.modifiers)<eptr.modifiers) then
  651. break;
  652. roi:=roi^.next;
  653. end;
  654. end;
  655. {Now generate the leave/enter events}
  656. if roi<>gpm_current_roi then
  657. begin
  658. if (gpm_current_roi<>nil) and (gpm_current_roi^.eventmask and GPM_LEAVE<>0) then
  659. begin
  660. backevent.eventtype:=GPM_LEAVE;
  661. gpm_current_roi^.handler(backevent,gpm_current_roi^.clientdata);
  662. end;
  663. if (roi<>nil) and (roi^.eventmask and GPM_ENTER<>0) then
  664. begin
  665. backevent.eventtype:=GPM_ENTER;
  666. roi^.handler(backevent,roi^.clientdata);
  667. end;
  668. end;
  669. gpm_current_roi:=roi;
  670. {events not requested are discarded}
  671. if (roi<>nil) and (eptr.eventtype and ($0f or GPM_ENTER or GPM_LEAVE) and roi^.eventmask=0) then
  672. gpm_handle_roi:=0
  673. else
  674. begin
  675. backevent:=eptr; {copy it, so the main one is unchanged}
  676. if roi=nil then
  677. if gpm_roi_handler<>nil then
  678. gpm_handle_roi:=gpm_roi_handler(backevent,gpm_roi_data)
  679. else
  680. gpm_handle_roi:=0
  681. else
  682. begin
  683. {Ok, now report the event as it is, after modifying x and y}
  684. dec(backevent.x,roi^.xmin);
  685. dec(backevent.y,roi^.ymin);
  686. roi^.handler(backevent,roi^.clientdata);
  687. end;
  688. end;
  689. end;
  690. function gpm_pushroi(x1:longint;y1:longint;x2:longint;y2:longint;
  691. mask:longint;fun:Tgpmhandler;xtradata:pointer):Pgpm_roi;
  692. var n:Pgpm_roi;
  693. begin
  694. {create a roi and push it}
  695. new(n);
  696. {use the roi handler, if still null}
  697. if (gpm_roi<>nil) and (gpm_handler<>nil) then
  698. gpm_handler:=@gpm_handle_roi;
  699. n^.xmin:=x1; n^.xmax:=x2;
  700. n^.ymin:=y1; n^.ymax:=y2;
  701. n^.minmod:=0; n^.maxmod:=$ffff;
  702. n^.prev:=nil; n^.next:=nil;
  703. n^.eventmask:=mask;
  704. n^.owned:=0; { use dispose }
  705. n^.handler:=fun;
  706. if xtradata=nil then
  707. n^.clientdata:=n
  708. else
  709. n^.clientdata:=xtradata;
  710. gpm_pushroi:=gpm_raiseroi(n,nil);
  711. end;
  712. function gpm_useroi(n:Pgpm_roi):Pgpm_roi;
  713. begin
  714. { use a Roi by pushing it }
  715. n^.prev:=nil;
  716. n^.next:=nil;
  717. n^.owned:=1;
  718. { use the roi handler, if still nil }
  719. if (gpm_roi=nil) and (gpm_handler=nil) then
  720. gpm_handler:=@gpm_handle_roi;
  721. gpm_useroi:=gpm_raiseroi(n,nil);
  722. end;
  723. function gpm_poproi(which:Pgpmroi):Pgpmroi;
  724. begin
  725. {extract the Roi and remove it}
  726. if which^.prev<>nil then
  727. which^.prev^.next:=which^.next;
  728. if which^.next<>nil then
  729. which^.next^.prev:=which^.prev;
  730. if gpm_roi=which then
  731. gpm_roi:=which^.next;
  732. if which^.owned=0 then
  733. dispose(which);
  734. if gpm_current_roi=which then
  735. gpm_current_roi:=nil;
  736. gpm_poproi:=gpm_roi; {return the new top-of-stack}
  737. end;
  738. function gpm_raiseroi(which:Pgpmroi;before:Pgpmroi):Pgpmroi;
  739. begin
  740. {raise a Roi above another, or to top-of-stack}
  741. if gpm_roi=nil then
  742. begin
  743. gpm_roi:=which;
  744. gpm_raiseroi:=which;
  745. exit;
  746. end;
  747. if before=nil then
  748. before:=gpm_roi;
  749. if before=which then
  750. begin
  751. gpm_raiseroi:=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^.prev:=before^.prev;
  761. before^.prev:=which;
  762. which^.next:=before;
  763. if which^.prev<>nil then
  764. which^.prev^.next:=which
  765. else
  766. gpm_roi:=which;
  767. gpm_raiseroi:=gpm_roi; { return the new top-of-stack }
  768. end;
  769. function gpm_lowerroi(which:Pgpmroi;after:Pgpmroi):Pgpmroi;
  770. begin
  771. {lower a Roi below another, or to bottom-of-stack}
  772. if after=nil then
  773. begin
  774. after:=gpm_roi;
  775. while after^.next<>nil do
  776. after:=after^.next;
  777. end;
  778. if after=which then
  779. begin
  780. gpm_lowerroi:=gpm_roi;
  781. exit;
  782. end;
  783. if which^.prev<>nil then
  784. which^.prev^.next:=which^.next;
  785. if which^.next<>nil then
  786. which^.next^.prev:=which^.prev;
  787. if gpm_roi=which then
  788. gpm_roi:=which^.next;
  789. which^.next:=after^.next;
  790. after^.next:=which;
  791. which^.prev:=after;
  792. if which^.next<>nil then
  793. which^.next^.prev:=which;
  794. gpm_lowerroi:=gpm_roi; {return the new top-of-stack}
  795. end;
  796. function gpm_getsnapshot(eptr:Pgpm_event):longint;
  797. var conn:Tgpm_connect;
  798. event:Tgpm_event;
  799. sillyset:Tfdset;
  800. i:longint;
  801. begin
  802. fillchar(conn,sizeof(conn),0);
  803. if eptr<>nil then
  804. conn.vc:=GPM_REQ_SNAPSHOT
  805. else
  806. begin
  807. conn.vc:=GPM_REQ_BUTTONS;
  808. eptr:=@event;
  809. end;
  810. if gpm_fd=-1 then
  811. begin
  812. gpm_getsnapshot:=-1;
  813. exit;
  814. end;
  815. fpFD_ZERO(sillyset);
  816. fpFD_SET(gpm_fd,sillyset);
  817. if fpselect(gpm_fd+1,@sillyset,nil,nil,0)=1 then
  818. gpm_getsnapshot:=0
  819. else
  820. begin
  821. fpwrite(gpm_fd,conn,sizeof(Tgpm_connect));
  822. i:=gpm_getevent(eptr^);
  823. if i<>1 then
  824. gpm_getsnapshot:=-1
  825. else
  826. begin
  827. gpm_getsnapshot:=eptr^.eventtype; { number of buttons }
  828. if eptr^.eventtype=0 then
  829. gpm_getsnapshot:=15;
  830. eptr^.eventtype:=0;
  831. end;
  832. end;
  833. end;
  834. function gpm_getsnapshot(var eptr:Tgpmevent):longint;inline;
  835. begin
  836. gpm_getsnapshot:=gpm_getsnapshot(@eptr);
  837. end;
  838. {$endif}
  839. end.