function TFPWMWindowManager.MainLoop(): cint;
var
  ev: TXEvent;
begin
  {$ifdef FPWM_TRACE}
  FPWMTrace('[TFPWMWindowManager.MainLoop]');
  {$endif}
  m_looping := True;
  while (m_looping) do
  begin
        nextEvent(@ev);
	m_currentTime := CurrentTime;
	case (ev._type) of
	ButtonPress:
	    eventButton(@ev.xbutton);
	ButtonRelease:
	begin
        end;
	MapRequest:
	    eventMapRequest(@ev.xmaprequest);
	ConfigureRequest:
	    eventConfigureRequest(@ev.xconfigurerequest);
	UnmapNotify:
	    eventUnmap(@ev.xunmap);
	CreateNotify:
	    eventCreate(@ev.xcreatewindow);
	DestroyNotify:
	    eventDestroy(@ev.xdestroywindow);
	ClientMessage:
	    eventClient(@ev.xclient);
	ColormapNotify:
	    eventColormap(@ev.xcolormap);
	PropertyNotify:
	    eventProperty(@ev.xproperty);
	SelectionClear:
	    WriteLn('fpwm: SelectionClear (this should not happen)');
	SelectionNotify:
            WriteLn('fpwm: SelectionNotify (this should not happen)');
	SelectionRequest:
            WriteLn('fpwm: SelectionRequest (this should not happen)');
	EnterNotify, LeaveNotify:
	    eventEnter(@ev.xcrossing);
	ReparentNotify:
	    eventReparent(@ev.xreparent);
	FocusIn:
	    eventFocusIn(@ev.xfocus);
	Expose:		
	    eventExposure(@ev.xexpose);
	MotionNotify:
        begin
	    if (CONFIG_AUTO_RAISE and m_focusChanging) then
            begin
		if (not m_focusPointerMoved) then m_focusPointerMoved := True
		else m_focusPointerNowStill := False;
	    end;
        end;
	FocusOut,
	 ConfigureNotify,
	 MapNotify,
	 MappingNotify:
	begin
        end;
	else
	    if (ev._type = m_shapeEvent) then
		WriteLn('fpwm: shaped windows are not supported')
	    else
               	WriteLn(Format('fpwm: unsupported event type %d', [ev._type]));
	end;
    end;
    release();
    Result := m_returnCode;
end;
procedure TFPWMWindowManager.nextEvent(e: PXEvent);
label waiting;
var
  fd: cint;
  rfds: Tfdset;
  t: TTimeval;
  tmpt: PTimeval;
  r: cint;
begin
  {$ifdef FPWM_TRACE}
  FPWMTrace('[TFPWMWindowManager.nextEvent]');
  {$endif}
    if (m_signalled = 0) then
    begin
    waiting:
	if (QLength(m_display) > 0) then
        begin
	    XNextEvent(m_display, e);
	    Exit;
	end;
	fd := ConnectionNumber(m_display);
	FillChar(rfds, 0, sizeof(rfds)); 
	fpFD_SET(fd, rfds);
	t.tv_sec := 0;
        t.tv_usec := 0;
	if (fpselect(fd + 1, @rfds, nil, nil, @t) = 1) then
        begin
	    XNextEvent(m_display, e);
	    Exit;
	end;
	XFlush(m_display);
	fpFD_SET(fd, rfds);
	t.tv_sec := 0; t.tv_usec := 20000;
        if m_focusChanging then tmpt := @t
        else tmpt := nil;
	r := fpselect(fd + 1, @rfds, nil, nil, tmpt);
        if r = 1 then
        begin
	    XNextEvent(m_display, e);
	    Exit;
	end;
	if (CONFIG_AUTO_RAISE and m_focusChanging) then 
	    checkDelaysForFocus();
	if (r = 0) then goto waiting;
	if (errno <> ESysEIntr ) or (m_signalled = 0) then
        begin
	    WriteLn('fpwm: select failed');
	    m_looping := False;
	end;
    end;
    WriteLn('fpwm: signal caught, exiting');
    m_looping := False;
    m_returnCode := 0;
end;
procedure TFPWMWindowManager.checkDelaysForFocus();
var
    t: cint;
begin
  {$ifdef FPWM_TRACE}
  FPWMTrace('[TFPWMWindowManager.checkDelaysForFocus]');
  {$endif}
  if not CONFIG_AUTO_RAISE then Exit;
  t := timestamp(True);
  if (m_focusPointerMoved) then 
  begin
    if (t < m_focusTimestamp) or
	(t - m_focusTimestamp > CONFIG_POINTER_STOPPED_DELAY) then
    begin
      if (m_focusPointerNowStill) then
      begin
	m_focusCandidate.focusIfAppropriate(True);
      end else m_focusPointerNowStill := True; 
    end;
  end
  else
  begin
    if (t < m_focusTimestamp) or
	(t - m_focusTimestamp > CONFIG_AUTO_RAISE_DELAY) then
    begin
      m_focusCandidate.focusIfAppropriate(True);
    end;
  end;
end;
procedure TFPWMWindowManager.considerFocusChange(c: TFPWMClient; w: TWindow; atimestamp: x.TTime);
begin
  {$ifdef FPWM_TRACE}
  FPWMTrace('[TFPWMWindowManager.considerFocusChange]');
  {$endif}
    if not CONFIG_AUTO_RAISE then Exit;
    if (m_focusChanging) then
	stopConsideringFocus();
    m_focusChanging := True;
    m_focusTimestamp := atimestamp;
    m_focusCandidate := c;
    m_focusCandidateWindow := w;
    m_focusPointerMoved := False;
    m_focusPointerNowStill := False;
    m_focusCandidate.selectOnMotion(m_focusCandidateWindow, True);
end;
procedure TFPWMWindowManager.stopConsideringFocus();
begin
  {$ifdef FPWM_TRACE}
  FPWMTrace('[TFPWMWindowManager.stopConsideringFocus]');
  {$endif}
    if not CONFIG_AUTO_RAISE then Exit;
    m_focusChanging := False;
    if m_focusChanging and (m_focusCandidateWindow <> 0) then
    begin
	m_focusCandidate.selectOnMotion(m_focusCandidateWindow, False);
    end;
end;
procedure TFPWMWindowManager.eventConfigureRequest(e: PXConfigureRequestEvent);
var
  wc: TXWindowChanges;
  c: TFPWMClient;
begin
  {$ifdef FPWM_TRACE}
  FPWMTrace('[TFPWMWindowManager.eventConfigureRequest]');
  {$endif}
  c := windowToClient(e^.window);
  e^.value_mask := e^.value_mask and not CWSibling;
  if (c <> nil) then c.eventConfigureRequest(e)
  else
  begin
    wc.x := e^.x;
    wc.y := e^.y;
    wc.width  := e^.width;
    wc.height := e^.height;
    wc.border_width := 0;
    wc.sibling := None;
    wc.stack_mode := Above;
    e^.value_mask := e^.value_mask and not CWStackMode;
    e^.value_mask := e^.value_mask or CWBorderWidth;
    XConfigureWindow(display(), e^.window, e^.value_mask, @wc);
  end;
end;
procedure TFPWMWindowManager.eventMapRequest(e: PXMapRequestEvent);
var
  c: TFPWMClient;
begin
  {$ifdef FPWM_TRACE}
  FPWMTrace('[TFPWMWindowManager.eventMapRequest]');
  {$endif}
  c := windowToClient(e^.window);
  if (c <> nil) then c.eventMapRequest(e)
  else
    WriteLn('fpwm: bad map request for window %d', e^.window); 
end;
procedure TFPWMWindowManager.eventUnmap(e: PXUnmapEvent);
var
  c: TFPWMClient;
begin
  {$ifdef FPWM_TRACE}
  FPWMTrace('[TFPWMWindowManager.eventUnmap]');
  {$endif}
  c := windowToClient(e^.window);
  if c <> nil then c.eventUnmap(e);
end;
procedure TFPWMWindowManager.eventCreate(e: PXCreateWindowEvent);
var
  c: TFPWMClient;
begin
  {$ifdef FPWM_TRACE}
  FPWMTrace('[TFPWMWindowManager.eventCreate]');
  {$endif}
  if (e^.override_redirect <> 0) then Exit;
  c := windowToClient(e^.window, True);
end;
procedure TFPWMWindowManager.eventDestroy(e: PXDestroyWindowEvent);
var
  c: TFPWMClient;
  i: Integer;
begin
  {$ifdef FPWM_TRACE}
  FPWMTrace('[TFPWMWindowManager.eventDestroy]');
  {$endif}
  c := windowToClient(e^.window);
  if (c <> nil) then
  begin
    if CONFIG_AUTO_RAISE and m_focusChanging and (c = m_focusCandidate) then
	m_focusChanging := False;
    for i := m_clients.count-1 downto 0 do
    begin
	if (m_clients.items[i] = c) then
        begin
	    m_clients.delete(i);
	    break;
	end;
    end;
    c.release();
    ignoreBadWindowErrors := True;
    XSync(display(), False);
    ignoreBadWindowErrors := False;
  end;
end;
procedure TFPWMWindowManager.eventClient(e: PXClientMessageEvent);
var
  c: TFPWMClient;
begin
  {$ifdef FPWM_TRACE}
  FPWMTrace('[TFPWMWindowManager.eventClient]');
  {$endif}
  c := windowToClient(e^.window);
    if (e^.message_type = Atoms.wm_changeState) then
    begin
	if (c <> nil) and (e^.format = 32) and (e^.data.l[0] = IconicState) then
        begin
	    if (c.isNormal()) then c.hide();
	    Exit;
	end;
    end;
  WriteLn('fpwm: unexpected XClientMessageEvent');
end;
procedure TFPWMWindowManager.eventColormap(e: PXColormapEvent);
var
  c: TFPWMClient;
  i: cint;
begin
  {$ifdef FPWM_TRACE}
  FPWMTrace('[TFPWMWindowManager.eventColormap]');
  {$endif}
  c := windowToClient(e^.window);
  if (e^.c_new <> 0) then  
  begin
    if (c <> nil) then c.eventColormap(e)
    else
    begin
	for i := 0 to m_clients.count - 1 do
	    m_clients.items[i].eventColormap(e);
    end;
  end;
end;
procedure TFPWMWindowManager.eventProperty(e: PXPropertyEvent);
var
  c: TFPWMClient;
begin
  {$ifdef FPWM_TRACE}
  FPWMTrace('[TFPWMWindowManager.eventProperty]');
  {$endif}
  c := windowToClient(e^.window);
  if (c <> nil) then c.eventProperty(e);
end;
procedure TFPWMWindowManager.eventReparent(e: PXReparentEvent);
begin
  {$ifdef FPWM_TRACE}
  FPWMTrace('[TFPWMWindowManager.eventReparent]');
  {$endif}
  if (e^.override_redirect <> 0) then Exit;
  windowToClient(e^.window, True); 
end;
procedure TFPWMWindowManager.eventEnter(e: PXCrossingEvent);
var
  c: TFPWMClient;
begin
  {$ifdef FPWM_TRACE}
  FPWMTrace('[TFPWMWindowManager.eventEnter]');
  {$endif}
  if (e^._type <> EnterNotify) then Exit;
  while (XCheckMaskEvent(m_display, EnterWindowMask, PXEvent(e))) do ;
  m_currentTime := e^.time;	
  c := windowToClient(e^.window);
  if (c <> nil) then c.eventEnter(e);
end;
procedure TFPWMWindowManager.eventFocusIn(e: PXFocusInEvent);
var
  c: TFPWMClient;
begin
  {$ifdef FPWM_TRACE}
  FPWMTrace('[TFPWMWindowManager.eventFocusIn]');
  {$endif}
  if (e^.detail <> NotifyNonlinearVirtual) then Exit;
  c := windowToClient(e^.window);
  if (c <> nil) then c.eventFocusIn(e);
end;
procedure TFPWMWindowManager.eventExposure(e: PXExposeEvent);
var
  c: TFPWMClient;
begin
  {$ifdef FPWM_TRACE}
  FPWMTrace('[TFPWMWindowManager.eventExposure]');
  {$endif}
  if (e^.count <> 0) then Exit;
  c := windowToClient(e^.window);
  if (c <> nil) then c.eventExposure(e);
end;
