1 { Copyright (C) 2005 Bas Steendijk and Peter Green
\r 
   2   For conditions of distribution and use, see copyright notice in zlib_license.txt
\r 
   3   which is included in the package
\r 
   4   ----------------------------------------------------------------------------- }
\r 
   9 lcore compatible interface for windows
\r 
  16 //note: events after release are normal and are the apps responsibility to deal with safely
\r 
  20     classes,windows,mmsystem;
\r 
  25     tlcomponent = class(tcomponent)
\r 
  29       destructor destroy; override;
\r 
  32     tltimer=class(tlcomponent)
\r 
  35       procedure setenabled(newvalue : boolean);
\r 
  37       ontimer:tnotifyevent;
\r 
  38       initialevent:boolean;
\r 
  39       initialdone:boolean;
\r 
  42       interval:integer;        {miliseconds, default 1000}
\r 
  44       property enabled:boolean read fenabled write setenabled;
\r 
  45       constructor create(aowner:tcomponent);override;
\r 
  46       destructor destroy;override;
\r 
  49     ttaskevent=procedure(wparam,lparam:longint) of object;
\r 
  51     tltask=class(tobject)
\r 
  53       handler  : ttaskevent;
\r 
  58       constructor create(ahandler:ttaskevent;aobj:tobject;awparam,alparam:longint);
\r 
  61 procedure messageloop;
\r 
  62 procedure addtask(ahandler:ttaskevent;aobj:tobject;awparam,alparam:longint);
\r 
  63 procedure disconnecttasks(aobj:tobject);
\r 
  64 procedure exitmessageloop;
\r 
  65 procedure processmessages;
\r 
  68   onshutdown:procedure(s:string);
\r 
  81   WINMSG_TASK=WM_USER;
\r 
  86   timesubstract:integer;
\r 
  87   firsttask,lasttask,currenttask:tltask;
\r 
  89 procedure tlcomponent.release;
\r 
  94 destructor tlcomponent.destroy;
\r 
  96   disconnecttasks(self);
\r 
 100 {------------------------------------------------------------------------------}
\r 
 102 procedure tltimer.setenabled(newvalue : boolean);
\r 
 104   fenabled := newvalue;
\r 
 106   initialdone := false;
\r 
 109 constructor tltimer.create;
\r 
 111   inherited create(AOwner);
\r 
 112   nexttimer := firsttimer;
\r 
 115   if assigned(nexttimer) then nexttimer.prevtimer := self;
\r 
 116   firsttimer := self;
\r 
 123 destructor tltimer.destroy;
\r 
 125   if prevtimer <> nil then begin
\r 
 126     prevtimer.nexttimer := nexttimer;
\r 
 128     firsttimer := nexttimer;
\r 
 130   if nexttimer <> nil then begin
\r 
 131     nexttimer.prevtimer := prevtimer;
\r 
 136 {------------------------------------------------------------------------------}
\r 
 138 function wcore_timehandler:integer;
\r 
 143   currenttimer,temptimer:tltimer;
\r 
 145   if not assigned(firsttimer) then begin
\r 
 150   tvnow := timegettime;
\r 
 151   if (tvnow and ((-1) shl rollover_bits)) <> timesubstract then begin
\r 
 152     currenttimer := firsttimer;
\r 
 153     while assigned(currenttimer) do begin
\r 
 154       dec(currenttimer.nextts,(1 shl rollover_bits));
\r 
 155       currenttimer := currenttimer.nexttimer;
\r 
 157     timesubstract := tvnow and ((-1) shl rollover_bits);
\r 
 159   tvnow := tvnow and ((1 shl rollover_bits)-1);
\r 
 161   currenttimer := firsttimer;
\r 
 162   while assigned(currenttimer) do begin
\r 
 163     if tvnow >= currenttimer.nextts then begin
\r 
 164       if assigned(currenttimer.ontimer) then begin
\r 
 165         if currenttimer.enabled then begin
\r 
 166           if currenttimer.initialevent or currenttimer.initialdone then currenttimer.ontimer(currenttimer);
\r 
 167           currenttimer.initialdone := true;
\r 
 170       currenttimer.nextts := tvnow+currenttimer.interval;
\r 
 172     temptimer := currenttimer;
\r 
 173     currenttimer := currenttimer.nexttimer;
\r 
 174     if temptimer.released then temptimer.free;
\r 
 178   currenttimer := firsttimer;
\r 
 179   while assigned(currenttimer) do begin
\r 
 180     if currenttimer.nextts < tv then tv := currenttimer.nextts;
\r 
 181     currenttimer := currenttimer.nexttimer;
\r 
 183   result := tv-tvnow;
\r 
 184   if result < 15 then result := 15;
\r 
 187 {------------------------------------------------------------------------------}
\r 
 189 constructor tltask.create(ahandler:ttaskevent;aobj:tobject;awparam,alparam:longint);
\r 
 192   handler   := ahandler;
\r 
 196   {nexttask  := firsttask;
\r 
 197   firsttask := self;}
\r 
 198   if assigned(lasttask) then begin
\r 
 199     lasttask.nexttask := self;
\r 
 202     postmessage(hwndwcore,WINMSG_TASK,0,0);
\r 
 205   //ahandler(wparam,lparam);
\r 
 208 procedure addtask(ahandler:ttaskevent;aobj:tobject;awparam,alparam:longint);
\r 
 210   tltask.create(ahandler,aobj,awparam,alparam);
\r 
 213 procedure disconnecttasks(aobj:tobject);
\r 
 215   currenttasklocal : tltask ;
\r 
 218   for counter := 0 to 1 do begin
\r 
 219     if counter = 0 then begin
\r 
 220       currenttasklocal := firsttask; //main list of tasks
\r 
 222       currenttasklocal := currenttask; //needed in case called from a task
\r 
 224     // note i don't bother to sestroy the links here as that will happen when
\r 
 225     // the list of tasks is processed anyway
\r 
 226     while assigned(currenttasklocal) do begin
\r 
 227       if currenttasklocal.obj = aobj then begin
\r 
 228         currenttasklocal.obj := nil;
\r 
 229         currenttasklocal.handler := nil;
\r 
 231       currenttasklocal := currenttasklocal.nexttask;
\r 
 240   if firsttask = nil then exit;
\r 
 242   currenttask := firsttask;
\r 
 245   while assigned(currenttask) do begin
\r 
 246     if assigned(currenttask.handler) then currenttask.handler(currenttask.wparam,currenttask.lparam);
\r 
 247     temptask := currenttask;
\r 
 248     currenttask := currenttask.nexttask;
\r 
 251   currenttask := nil;
\r 
 254 {------------------------------------------------------------------------------}
\r 
 256 procedure exitmessageloop;
\r 
 258   postmessage(hwndwcore,WM_QUIT,0,0);
\r 
 261   {$ifdef threadtimer}
\r 
 264 const timerid_wcore=$1000;
\r 
 267 function MyWindowProc(
\r 
 271     alParam : LPARAM): Integer; stdcall;
\r 
 276   Result := 0;  // This means we handled the message
\r 
 278   {MsgRec.hwnd    := ahWnd;}
\r 
 279   MsgRec.wParam  := awParam;
\r 
 280   MsgRec.lParam  := alParam;
\r 
 284     {$ifndef threadtimer}
\r 
 286       if msgrec.wparam = timerid_wcore then begin
\r 
 287         a := wcore_timehandler;
\r 
 288         killtimer(hwndwcore,timerid_wcore);
\r 
 289         settimer(hwndwcore,timerid_wcore,a,nil);
\r 
 294     {WINMSG_TASK:dotasks;}
\r 
 303       Result := DefWindowProc(ahWnd, auMsg, awParam, alParam)
\r 
 309   MyWindowClass : TWndClass = (style         : 0;
\r 
 310                                  lpfnWndProc   : @MyWindowProc;
\r 
 317                                  lpszMenuName  : nil;
\r 
 318                                  lpszClassName : 'wcoreClass');
\r 
 320 procedure messageloop;
\r 
 325   if Windows.RegisterClass(MyWindowClass) = 0 then halt;
\r 
 326   //writeln('about to create wcore handle, hinstance=',hinstance);
\r 
 327   hwndwcore := CreateWindowEx(WS_EX_TOOLWINDOW,
\r 
 328                                MyWindowClass.lpszClassName,
\r 
 329                                '',        { Window name   }
\r 
 330                                WS_POPUP,  { Window Style  }
\r 
 332                                0, 0,      { Width, Height }
\r 
 335                                HInstance, { hInstance     }
\r 
 336                                nil);      { CreateParam   }
\r 
 338   if hwndwcore = 0 then halt;
\r 
 340   {$ifdef threadtimer}
\r 
 343   if settimer(hwndwcore,timerid_wcore,15,nil) = 0 then halt;
\r 
 347   while GetMessage(MsgRec, 0, 0, 0) do begin
\r 
 348     TranslateMessage(MsgRec);
\r 
 349     DispatchMessage(MsgRec);
\r 
 350     {if not peekmessage(msgrec,0,0,0,PM_NOREMOVE) then onidle}
\r 
 353   if hWndwcore <> 0 then begin
\r 
 354     DestroyWindow(hwndwcore);
\r 
 358   {$ifdef threadtimer}
\r 
 361   killtimer(hwndwcore,timerid_wcore);
\r 
 365 function ProcessMessage : Boolean;
\r 
 370     if PeekMessage(Msg, hwndwcore, 0, 0, PM_REMOVE) then begin
\r 
 372       DispatchMessage(Msg);
\r 
 376 procedure processmessages;
\r 
 378   while processmessage do;
\r