{
	This file is part of the Mufasa Macro Library (MML)
	Copyright (c) 2009 by Raymond van Venetië and Merlijn Wajer

    MML is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    MML is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with MML.  If not, see <http://www.gnu.org/licenses/>.

	See the file COPYING, included in this distribution,
	for details about the copyright.

    WindowSelector for the Mufasa Macro Library
}

unit windowselector;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils,
  {$IFDEF MSWINDOWS} os_windows, {$ENDIF}
  {$IFDEF LINUX} os_linux,  ctypes, {$ENDIF}
  controls,
  graphics,
  forms,
  extctrls,
  {$IFNDEF MSWINDOWS}x, xlib,xatom,
  {$ELSE}
  windows,
  {$ENDIF}
  mufasabase

  ;

type
    TMWindowSelector = class(TObject)
          constructor Create(manager: TIOManager);
          destructor Destroy; override;

          function Drag: TNativeWindow;


    public
          LastPick: TNativeWindow;
          haspicked: boolean;
          manager: TIOManager;

    end;


implementation


constructor TMWindowSelector.Create(manager: TIOManager);
begin
  inherited create;
  haspicked:= false;
  self.manager := manager;

end;


destructor TMWindowSelector.Destroy;
begin

  inherited;
end;

{$IFDEF LINUX}
function TMWindowSelector.Drag: TNativeWindow;
var
  Tempwindow : x.TWindow;
  root : x.TWindow;
  subwindow : x.TWindow;
  x_root, y_root : cint;
  xmask : cuint;
  x, y : cint;
  //Old_Handler : TXErrorHandler;

  window_opacity: TAtom;
  opacity_75: culong;
  opacity_100: culong;

begin
  //Old_Handler := XSetErrorHandler(@MufasaXErrorHandler);

  Result := 0;

  window_opacity:=XInternAtom(manager.display,PChar('_NET_WM_WINDOW_OPACITY'), False);
  opacity_75 := cuint($ffffffff * 0.75);
  opacity_100 := cuint($ffffffff);

  repeat
    // get pointer pos + current window we are at.
    XQueryPointer(manager.display, manager.desktop, @root,
                @Tempwindow, @x_root, @y_root,
                @x, @y, @xmask);
    subwindow:= Tempwindow;

    while subwindow <> 0 do
    begin
        Tempwindow := subwindow;
        XQueryPointer(manager.display, Tempwindow, @root,
                 @subwindow, @x_root, @y_root,
                 @x, @y, @xmask);
    end;



    if Result <> Tempwindow then
    begin
      mDebugLn('Making ' + inttostr(tempwindow) + ' transparent');
      XChangeProperty(manager.display, tempwindow, window_opacity, XA_CARDINAL, 32, PropModeReplace, @opacity_75, 1);

      mDebugLn('Resetting ' + inttostr(Result));
      if result <> 0 then
        XChangeProperty(manager.display, Result, window_opacity, XA_CARDINAL, 32, PropModeReplace, @opacity_100, 1);
      mDebugLn('Changing Window from: ' +  Inttostr(result) +' to: ' + IntToStr(Tempwindow));
     // XChangeProperty(Window.XDisplay, tempwindow, window_opacity, XA_CARDINAL, 32, PropModeReplace, @opacity_50, 1);

      Result := Tempwindow;
      LastPick:= TempWindow;
      haspicked:= true;
    end;
    XFlush(manager.display);
    Sleep(16);

    //if we are selecting for a long time, we must still process other messages
    Application.ProcessMessages;

  until (xmask and Button1Mask) = 0;

  XChangeProperty(manager.display, Result, window_opacity, XA_CARDINAL, 32, PropModeReplace, @opacity_100, 1);
  XFlush(manager.display);

  //XSetErrorHandler(Old_handler);
end;

{$ELSE}

function TMWindowSelector.Drag: TNativeWindow;
var
  TargetRect: TRect;
  Region : HRGN;
  Cursor : TCursor;
  TempHandle : Hwnd;
  Handle : Hwnd;
  DragForm : TForm;
  EdgeForm : TForm;
  Style : DWord;
  W,H: integer;
const
  EdgeSize =4;
  WindowCol = clred;
begin;
  Cursor:= Screen.Cursor;
  Screen.Cursor:= crCross;
  TempHandle := GetDesktopWindow;
  EdgeForm := TForm.Create(nil);
  EdgeForm.Color:= WindowCol;
  EdgeForm.BorderStyle:= bsNone;
  EdgeForm.Show;

  DragForm := TForm.Create(nil);
  DragForm.Color:= WindowCol;
  DragForm.BorderStyle:= bsNone;
  DragForm.Show;

  Style := GetWindowLong(DragForm.Handle, GWL_EXSTYLE);
  SetWindowLong(DragForm.Handle, GWL_EXSTYLE, Style or WS_EX_LAYERED or WS_EX_TRANSPARENT);
  SetLayeredWindowAttributes(DragForm.Handle, 0, 100, LWA_ALPHA);

  while GetAsyncKeyState(VK_LBUTTON) <> 0 do
  begin;
    Handle:= WindowFromPoint(Mouse.CursorPos);
    if (Handle <> TempHandle) and (Handle <> EdgeForm.Handle) then
    begin;
      GetWindowRect(Handle, TargetRect);
      W :=TargetRect.Right - TargetRect.Left+1;
      H :=TargetRect.Bottom - TargetRect.Top+1;
      DragForm.SetBounds(TargetRect.Left,TargetRect.top,W,H);//Draw the transparent form

      SetWindowRgn(EdgeForm.Handle,0,false);//Delete the old region
      Region := CreateRectRgn(0,0,w-1,h-1); //Create a full region, of the whole form
      CombineRgn(Region,Region,CreateRectRgn(EdgeSize,EdgeSize,w-1-(edgesize),h-1-(edgesize)),RGN_XOR); //Combine a the 2 regions (of the full form and one without the edges)
      SetWindowRgn(edgeform.Handle,Region,true);//Set the only-edge-region!
      EdgeForm.SetBounds(TargetRect.Left,TargetRect.top,W,H);//Move the form etc..
      TempHandle  := Handle;
    end;
    Application.ProcessMessages;
    Sleep(30);
  end;
  Result := TempHandle;
  LastPick:= TempHandle;
  haspicked:= true;
  Screen.Cursor:= cursor;
  DragForm.Hide;
  DragForm.Free;
  EdgeForm.Hide;
  EdgeForm.Free;
end;
{$ENDIF}



end.

