Skip to content

Using Declares In Your Multi-Platform Desktop Apps

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