Linux - XFCE4 - Lazarus system wide hotkey - linux

I have done quite a bit of searching in Google and though I can find the switches to do this for Windows using WM_HOTKEY I cannot find it for Linux.
WM_HOTKEY Hook
uses ...,windows;
var
PrevWndProc: WNDPROC;
const
MY_ID=1;
function WndCallback(Ahwnd: HWND; uMsg: UINT; wParam: WParam; lParam: LParam):LRESULT; stdcall;
begin
if (uMsg=WM_HOTKEY) and (WParam=MY_ID) then
begin
Application.Restore;
end;
result:=CallWindowProc(PrevWndProc,Ahwnd, uMsg, WParam, LParam);
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
PrevWndProc:=Windows.WNDPROC(SetWindowLong(Self.Handle,GWL_WNDPROC,PtrInt(#WndCallback)));
RegisterHotKey(Self.Handle,MY_ID,0,vk_F9);
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
UnRegisterHotkey(Self.Handle,MY_ID);
end;
I am looking to place a system wide hotkey hook in XFCE4 and/or XWindows on a linux machine. I know it is possible as many screenshot programs do this all the time no matter what the Window Manager is.
I need for my app to be able to hook a key combo to activate something inside the app but I cannot find anything for this with Lazarus/Pascal on linux anywhere.

Marco knows more about FPC than most (think he wrote it).
In any event you may find the code at the link below helpful and/or other portions of the code base:
http://code.google.com/p/ovoplayer/source/browse/trunk/src/platform/darwin/mmkeys.inc?spec=svn206&r=206

Related

Creating MainForm on a TThread

I have a Delphi 2010 application that exports a DLL and has the library header. It creates its MainForm in a TThread, like so:
var
ActiveThread: TActive;
type
TActive= class(TThread)
protected
procedure Execute; override;
end;
procedure TActive.Execute;
begin
Application.Initialize;
Application.CreateForm(MyForm, form);
Application.Run;
end;
begin
ActiveThread := TActive.Create(true);
ActiveThread.FreeOnTerminate := true;
ActiveThread.Resume;
end.
Whenever I load this DLL through the LoadLibrary function, the application runs fine. (Apparently it uses the thread that I passed to LoadLibrary as the main thread and has no issues)
But if I attempt to export this DLL to an actual EXE, by changing the generated output in Options -> Application. and changing the header from library to program and then build it and execute the output EXE instead of loading the DLL through the windows api, the application hangs when attempting to create the form, specifically at Application.CreateForm(MyForm, form);. If I remove the Application initialization from the thread and place it on the main routine, it runs just fine.
The form I'm trying to render is just an empty form. Any ideas?
When compiling this code as a program, at runtime it will try to terminate itself when end. is reached, before the worker thread even has a chance to run, which could possibly (and likely) happen after the Application object has been destroyed. You would have to wait for the worker thread to finish its work before letting the program exit, eg:
program MyProgram;
uses
Classes, Forms, MyForm;
type
TActive = class(TThread)
protected
procedure Execute; override;
end;
procedure TActive.Execute;
begin
Application.Initialize;
Application.CreateForm(TMyForm, MyForm);
Application.Run;
end;
var
ActiveThread: TActive;
begin
ActiveThread := TActive.Create(False);
ActiveThread.WaitFor;
ActiveThread.Free;
end.
But, there is really no good reason to ever use a worker thread like this, this defeats the whole purpose of using a thread, so you may as well just get rid of it altogether:
program MyProgram;
uses
Forms, MyForm;
begin
Application.Initialize;
Application.CreateForm(TMyForm, MyForm);
Application.Run;
end.
On the other hand, if you are trying to share common code between program and library projects, then you can wrap the Application code inside of a function and let the project decide which thread calls the function, eg:
unit MyApp;
interface
procedure RunMyApp;
implementation
uses
Forms, MyForm;
procedure RunMyApp;
begin
Application.Initialize;
Application.CreateForm(TMyForm, MyForm);
Application.Run;
end;
end.
program MyProgram;
uses
MyApp;
begin
RunMyApp;
end.
library MyLibrary
uses
Classes, MyApp;
type
TActive = class(TThread)
protected
procedure Execute; override;
end;
procedure TActive.Execute;
begin
RunMyApp;
end;
var
ActiveThread: TActive;
begin
ActiveThread := TActive.Create(True);
ActiveThread.FreeOnTerminate := True;
ActiveThread.Resume;
end.

Setup Programs created using Inno Setup Compiler doesn't display Minimize Animation

My Problem is why Inno Setup Compiler (Unicode or ANSI) and any Setups made by it don't minimize showing a nice Minimizing Animation like in Other Windows Programs?
It displays a very basic Minimize Animation..........Why that?
I know Borland Delphi as Inno Setup Compiler's Compiler, but Borland Delphi doesn't have such a bad Minimize Animation...........It minimizes normally as Windows System Windows minimize (such as Explorer, Computer, Control Panel).................
I also noticed that the Windows Installer Creater Nullsoft Scriptable Install System - NSIS and Setups made using it are also minimizing well like I said.
How can I resolve this problem?
UPDATED QUESTION
I also added a code to play that nice Zooming Minimize / Restore Animation can be seen in Many Windows Applications on Inno Setup's WizardForm, But when I click the WizardForm's Minimize Button after adding this code to Inno Setup Compiler's Source Code, the Nice Zooming animation not plays and it never can be minimized using it, it only can be minimized using Taskbar button after adding this code. So it means this code not working or anything else wrong...........Why this is not working???
The Code I Added to unit WizardForm:
interface
uses
Windows;
type
TTrayZoom = class(TObject)
private
class function GetTrayRect: TRect;
class procedure DoZoom(const Wnd: HWND; const Src, Dest: TRect);
public
class procedure ZoomToTray(const Wnd: HWND);
class procedure ZoomFromTray(const Wnd: HWND);
end;
implementation
class procedure TTrayZoom.DoZoom(const Wnd: HWND; const Src, Dest: TRect);
begin
DrawAnimatedRects(Wnd, IDANI_CAPTION, Src, Dest);
end;
class function TTrayZoom.GetTrayRect: TRect;
var
TaskbarWnd, TrayWnd: HWND;
begin
TaskbarWnd := FindWindow('Shell_TrayWnd', nil);
TrayWnd := FindWindowEx(TaskbarWnd, 0, 'TrayNotifyWnd', nil);
GetWindowRect(TrayWnd, Result);
end;
class procedure TTrayZoom.ZoomFromTray(const Wnd: HWND);
var
WndRect: TRect;
begin
GetWindowRect(Wnd, WndRect);
DoZoom(Wnd, GetTrayRect, WndRect);
end;
class procedure TTrayZoom.ZoomToTray(const Wnd: HWND);
var
WndRect: TRect;
begin
GetWindowRect(Wnd, WndRect);
DoZoom(Wnd, WndRect, GetTrayRect);
end;
And I called TTrayZoom.ZoomToTray from if WMSysCommand..... = SCMINIMIZE and called TTrayZoom.ZoomFromTray from if WMSysCommand..... = SCRESTORE with the setting HWND parameter to WizardForm.Handle.
But those codes never works, I even don't know if they're get called or not. :(
What is the problem playing this Zooming Animation in this WizardForm?
I'd say there are two issues.
The animation is shown for windows that have a task bar button. The wizard form does not have a task bar button.
The task bar button of the installer belongs to a hidden main window.
Historically the installers had full screen background gradient blue windows. Even Inno Setup supported that.
While that background window is no longer enabled by default (the WindowVisible directive defaults to No in modern versions of Inno Setup), it still exists and owns the task bar button.
Inno Setup is built using an ancient version of Delphi that likely does not play nicely with the minimize feature.
Generally, I'd say you should file a feature request/bug report to get this fixed.

Semi-Transparent Wizard Form

I was working on an Inno Setup design when I faced this mighty question in front of me...How to make the Wizard form semi-transparent?
I know Delphi too so I'm thinking if there is any way we can use FMX's Fill.Color and transparency=true with Inno Setup?
I'm currently using this function for Wizard creation:
procedure CreateWizardForm;
begin
with WizardForm do begin
BorderStyle:=bsNone;
ClientWidth:=900;
ClientHeight:=540;
InnerNotebook.Hide;
OuterNotebook.Hide;
Center;
Bevel.Hide;
NextButton.Width:=0;
CancelButton.Width:=0;
end;
Form:=ImgLoad(WizardForm.Handle,ExpandConstant('{tmp}')+'\form.png',0,0,900,540,True,True);
end;
Regards
Ramiro
There is Inno Setup plug-in as for NSIS called IsWin7 or MegaFileUpload.
It works for Windows Vista and Windows 7 - both systems support Aero effects.
Keep in mind that iswin7.dll is non-official.
Sample:
[Files]
Source: ".\ISWin7.dll"; DestDir: "{tmp}"; Flags: dontcopy nocompression
[Code]
procedure iswin7_add_glass(Handle:HWND; Left, Top, Right, Bottom : Integer; GDIPLoadMode: boolean);
external 'iswin7_add_glass#files:iswin7.dll stdcall';
procedure iswin7_add_button(Handle:HWND);
external 'iswin7_add_button#files:iswin7.dll stdcall';
procedure iswin7_free;
external 'iswin7_free#files:iswin7.dll stdcall';
procedure InitializeWizard();
begin
iswin7_add_button(WizardForm.BackButton.Handle);
iswin7_add_button(WizardForm.NextButton.Handle);
iswin7_add_button(WizardForm.CancelButton.Handle);
iswin7_add_glass(WizardForm.Handle, 0, 0, 0, ScaleY(47), True);
end;
procedure DeinitializeSetup();
begin
iswin7_free;
end;
Is the feature you are trying to achieve called Aero (from Windows Vista)?
I think this is not possible to do in pure Inno Setup.
Check this NSIS plug-in: http://nsis.sourceforge.net/Aero_plug-in.
It is open source and uses some Windows API functions -- for inspiration.

Code to run after all files are installed

I got the following little function which I need to call after all files of the [Files] section have been copied
procedure DllAfterInstall(platform: Integer);
begin
if not installDriver(platform) then
MsgBox(ExpandConstant('{cm:installDriverFail}'), mbError, MB_OK);
end;
where installDriver(platform) is an external function to one of my dll's.
As soon as I try to call the DllAfterInstall function in the [Run] section like
Filename: "{code:DllAfterInstall}"; Parameters: 0; Check: not IsWin64
I got the error
Invalid prototype for 'DllAfterInstall'
So can anyone tell me what I'm doing wrong? Or maybe is there another way to call a *.dll after all files have been copied? The *.dll function should only be called once so AfterInstall is no option.
Call your code from CurStepChanged event function when CurStep is ssPostInstall:
procedure CurStepChanged(CurStep: TSetupStep);
begin
if CurStep = ssPostInstall then
begin
Log('Post install');
DllAfterInstall(platform);
end;
end;
You also need to provide an actual value to the platform parameter of the function.

Delphi IDE hangs when I create a thread

I have a problem that Delphi (2010) IDE and the program both hang during debugging when I run a thread.
Both windows do not respond. When I kill the program, IDE works again.
It took time, I had to delete pieces of my program and I found the problem.
It is caused by VirtualStringTree.
So if I put just empty VirtualStringTree (v. 5.5.3) on form, one button to execute TThread with just "Sleep(2000)" in Execute procedure and run such program under debugger, it hangs (usually at first click). When I remove the VST, it works.
I have also noticed that Windows Reporting Service is started but I haven't found anything in the Windows event log.
Does anyone have any idea how this is possible?
Full source here
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, VirtualTrees, StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
VirtualStringTree1: TVirtualStringTree;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
type
TTestThread = class(TThread)
private
{ Private declarations }
protected
procedure Execute; override;
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
{ TTestThread }
procedure TTestThread.Execute;
begin
FreeOnTerminate:=True;
Sleep(2000);
end;
{ TForm }
procedure TForm1.Button1Click(Sender: TObject);
begin
TTestThread.Create(False);
end;
end.
EDIT:
I have also tried to debug Delphi process. I attached from second to first IDE. When I click the button to start the thread, both IDEs hang. So I have tried with Delphi 7 which I also have installed. That worked. It stays in a loop somewhere in ntdll.NtWaitForMultipleObjects, KERNELBASE.WaitForMultipleObjectsEx, USER32.MsgWaitForMultipleObjects.
I have completely reinstalled Delphi, no change. It may also be related to this line in VirtualStringTree source: "WaitForSingleObject(WorkEvent, INFINITE);". When I remove it, it does not freeze. But I think it is necessary there.
Finally I installed Delphi XE and that works correctly. It is mysterious.
TTestThread is a descendant of TThread in your code but it still needs a variable declaration and a proper constructor call.
var
MyThread: TTestThread;
The proper call to instantiate it would be
MyThread := TTestThread.Create(False);
rather than trying to invoke the constructor as you have in the button click event.
Good luck and have fun.
RP

Resources