Sometimes you need a feature that is not available directly from the Xojo framework. Responding to this need is what Declares are designed for: to get access to system native APIs. On OS X, you typically look at the Cocoa APIs. On Windows, the Win32 APIs. Finally on Linux, the GTK APIs.
As an example, let’s say we desperately need to add transparency to one of your application windows. Here is how to proceed.
Find the Native API Documentation
You need to get to the right documentation for each native API.
COCOA
The source for Cocoa API is https://developer.apple.com/. Since we are looking for a window functionality, NSWindow is the class we need to review this, in which we’ll find our target ObjC method:
- (void)setAlphaValue:(CGFloat)windowAlpha
WIN32
The source for Win32 API is http://msdn.microsoft.com. Again, we want to focus on window functionalities, http://msdn.microsoft.com/en-us/library/windows/desktop/ms633540(v=vs.85).aspx in which we’ll find our target C function:
BOOL WINAPI SetLayeredWindowAttributes(In HWND hwnd, In COLORREF crKey, In BYTE bAlpha, In DWORD dwFlags);
GTK
The source for GTK API is http://developer.gimp.org/api/2.0/gtk/. Here again, we want to review functions related to GTKWindow http://developer.gimp.org/api/2.0/gtk/GtkWindow.html, in which we’ll find our target C method:
void gtk_window_set_opacity (GtkWindow *window, gdouble opacity);
Map to Xojo Code
In order to avoid wasting time understanding how these methods/functions work in real situation, it’s always efficient to google around to figure out how they are implemented in native code. There are tons of sample code you can review via Google. This way, you’ll figure out our Win32 call need an other one in order to work correctly: http://msdn.microsoft.com/en-us/library/windows/desktop/ms633591(v=vs.85).aspx declared this way:
LONG WINAPI SetWindowLong( _In_ HWND hWnd, _In_ int nIndex, _In_ LONG dwNewLong);
Most of the tricky part of using Declares is the ability to convert a C/C++/ObjC type to a type Xojo can handle. Fortunately, Xojo Documentation helps a lot. It provides detailed information about how to define a Declare, and a very handy types correspondences table.
Let’s start with Cocoa
Native, Objective-C method:- (void)setAlphaValue:(CGFloat)windowAlpha
CGFloat (in that case, possible values are 0.0 to 1.0) can be handled by the Xojo type Single
So our corresponding Declare in Xojo:
Declare Sub setAlphaValue Lib "Cocoa" selector "setAlphaValue:" _ (windowRef As Integer, windowAlpha As Single)
How you call it in Xojo:
setAlphaValue(Self.Handle, 0.4) //Here self refers to our Xojo Window instance
Now let’s deal with Win32
A valuable tip to figure out how to deal with Win32 API types is to review some widely available VB code that uses Declares. Most of the time this code will work in Xojo with no or a very few changes.
Native, C/C++ functions:
LONG SetWindowLong(HWND hWnd, int nIndex, LONG dwNewLong);BOOL SetLayeredWindowAttributes(HWND hwnd, COLORREF crKey, BYTE bAlpha, DWORD dwFlags);
Corresponding Declares in Xojo:
Declare Function SetWindowLong Lib "User32" Alias "SetWindowLongA" (ByVal hwnd As Integer, ByVal nIndex As Integer, ByVal dwNewLong As Integer) As Integer Declare Function SetLayeredWindowAttributes Lib "User32" (windowRef As Integer, ByVal crKey As Integer, ByVal Alpha As Byte, ByVal dwFlags As Integer) As Boolean
How you call them in Xojo:
Call SetWindowLong Self.Handle, GWL_EXSTYLE, styleCall SetLayeredWindowAttributes(Self.Handle, 0, Me.Value, LWA_ALPHA)
Finally, Linux
Native C method:
void gtk_window_set_opacity (GtkWindow *window, gdouble opacity);
Here a GTK ‘double’ (gdouble) logically corresponds to a Xojo Double.
Corresponding Declare in Xojo:
Declare Sub gtk_window_set_opacity lib "libgtk-x11-2.0.so" (windowRef As Integer, opacity as Double)
How you call it in Xojo:
gtk_window_set_opacity(Self.Handle, 0.4)
In order to get this method working, your Linux environment must run a composite manager. If not, this method will silently fail. If you want to check it before executing this method, add a Declare like this:
Declare Function gtk_widget_is_composited lib "libgtk-x11-2.0.so" (windowRef As Integer) As Boolean
So your code looks like this:
if gtk_widget_is_composited(Self.Handle) then gtk_window_set_opacity(Self.Handle, 0.4)end if
Setting up all together in your app.
Since these declares are designed to be compiled depending of the target platform, our code should be placed into pragma directives that indicate the compiler what should be taken in account depending of the current platform you are building for:
#if TargetCocoa then Declare Sub setAlphaValue Lib "Cocoa" selector "setAlphaValue:" (windowRef As Integer, windowAlpha As Single) setAlphaValue(Self.handle, TransparencySlider.Value / TransparencySlider.Maximum) #Elseif TargetWin32 dim GWL_EXSTYLE As Integer = (-20) dim WS_EX_RIGHT As Integer = &H1000 dim WS_EX_LEFTSCROLLBAR As Integer = &H4000 dim WS_EX_LAYERED As Integer = &H80000 dim LWA_ALPHA As Integer = &H2 dim LWA_COLORKEY As Integer =&H1 Declare Function SetWindowLong Lib "User32" Alias "SetWindowLongA" (ByVal hwnd As Integer, ByVal nIndex As Integer, ByVal dwNewLong As Integer) As Integer Declare Function SetLayeredWindowAttributes Lib "User32" (windowRef As Integer, ByVal crKey As Integer, ByVal Alpha As Byte, ByVal dwFlags As Integer) As Boolean Dim style As Integer style = style Or WS_EX_LAYERED Call SetWindowLong Self.Handle, GWL_EXSTYLE, style Call SetLayeredWindowAttributes(Self.Handle, 0, Me.Value, LWA_ALPHA) #Elseif TargetLinux dim wRef As Integer = Self.Handle dim opacityVal As Double = TransparencySlider.Value / TransparencySlider.Maximum
Declare Sub gtk_window_set_opacity lib "libgtk-x11-2.0.so" (windowRef As Integer, opacity as Double) Declare Function gtk_widget_is_composited lib "libgtk-x11-2.0.so" (windowRef As Integer) As Boolean if gtk_widget_is_composited(Self.Handle) then gtk_window_set_opacity(Self.Handle, opacityVal) else MsgBox "Not Composited" end if #Endif