How can I make a window transparent in OS X and Linux? (Windows already works)

1,175 views
Skip to first unread message

Remy Oukaour

unread,
Nov 1, 2014, 4:44:59 PM11/1/14
to fltkg...@googlegroups.com
I have a custom window class My_Window, with a View menu containing the usual options (toggle status bar, toggle fullscreen, etc), and now I'm adding a transparency toggle. I know how to use Win32 API calls to do this in Windows:

// class My_Window : Fl_Double_Window { ... }

void My_Window::transparent_cb(Fl_Menu_ *m, My_Window *w) {
    bool transparent = m->mvalue()->value();
    // Cross-platform: toggle window transparency between 80% and 100%
#if defined(_WIN32)
    HWND hwnd = fl_xid(w);
    LONG_PTR exstyle = GetWindowLongPtr(hwnd, GWL_EXSTYLE);
    if (!(exstyle & WS_EX_LAYERED)) {
        SetWindowLongPtr(hwnd, GWL_EXSTYLE, exstyle | WS_EX_LAYERED);
    }
    SetLayeredWindowAttributes(hwnd, 0, transparent ? 192 : 255, LWA_ALPHA);
#elif defined(__APPLE__)
    // Mac OS X with Cocoa: ???
#else
    // Linux with GTK+: ???
#endif
}

For the OS X and Linux parts, though, I'm stuck. I see that Fl_cocoa.mm contains this code:

@interface FLWindow : NSWindow {
  Fl_Window *w;
  BOOL containsGLsubwindow;
}

// ...

FLWindow *cw = [[FLWindow alloc] initWithFl_W:w
                contentRect:crect
                styleMask:winstyle];

// ...

if(w->menu_window()) { // make menu windows slightly transparent
  [cw setAlphaValue:0.97];
}

As far as I can tell, though, I can't just get an NSWindow via fl_xid(w) and pass it the setAlphaValue message in C++ alone; instead, I'll have to write a small Objective-C file to do that, and call it from my main file. Can someone who knows Objective-C and the Cocoa API please help me do this?

I also need to implement this function in Linux, using GTK+ since I already rely on it for the native file chooser, but I'm more likely to solve this myself since it's still just C++ calls -- looks like gtk_widget_set_opacity(GTK_WIDGET(fl_xid(w)), transparent ? 0.8 : 1.0); would work, but I haven't tested it.

Thank you,

-- Remy

Remy Oukaour

unread,
Nov 1, 2014, 7:37:31 PM11/1/14
to fltkg...@googlegroups.com
Okay, I figured out how to do this in OS X. Here's the callback:

#include "my-cocoa.h"

// ...


void My_Window::transparent_cb(Fl_Menu_ *m, My_Window *w) {
    bool transparent = m->mvalue()->value();
    // Cross-platform: toggle window transparency between 80% and 100%
#if defined(_WIN32)
    HWND hwnd = fl_xid(w);
    LONG_PTR exstyle = GetWindowLongPtr(hwnd, GWL_EXSTYLE);
    if (!(exstyle & WS_EX_LAYERED)) {
        SetWindowLongPtr(hwnd, GWL_EXSTYLE, exstyle | WS_EX_LAYERED);
    }
    SetLayeredWindowAttributes(hwnd, 0, transparent ? 192 : 255, LWA_ALPHA);
#elif defined(__APPLE__)
    setWindowTransparency(w, transparent ? 0.8 : 1.0);

#else
    // Linux with GTK+: ???
#endif
}

Then I created my-cocoa.h:

#ifndef MY_COCOA_H
#define MY_COCOA_H

#include <FL/x.H>
#include <FL/Fl_Window.H>

void setWindowTransparency(Fl_Window *w, double alpha);

#endif

And my-cocoa.mm:

#include "my-cocoa.h"

void setWindowTransparency(Fl_Window *w, double alpha) {
    [fl_xid(w) setAlphaValue:alpha];
}

Hopefully this will help anyone else writing cross-platform apps.

Greg Ercolano

unread,
Nov 1, 2014, 9:18:04 PM11/1/14
to fltkg...@googlegroups.com
On 11/01/14 16:37, Remy Oukaour wrote:
> Okay, I figured out how to do this in OS X. Here's the callback:
> [good info snipped]
> Hopefully this will help anyone else writing cross-platform apps.

I'd like to think we can merge this into the API at some point,
perhaps after the 1.3.3 release goes out in the next few days.

If we can get consensus from the devs, it can be added.

Kevin Ingwersen (Ingwie Phoenix)

unread,
Nov 2, 2014, 11:19:08 AM11/2/14
to fltkg...@googlegroups.com
> --
> You received this message because you are subscribed to the Google Groups "fltk.general" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to fltkgeneral...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.

I can see this being an API. Websites have been using rgba()/opacity for a while now. Seeing FLTK have a similar ability looks like something nice.

class Fl_Widget {
// …
bool canBeTransparent();
void setTransparency(float);
};

^ would be a suggestion. It seems that OS X and WinAPI both use floats for the percentage (0.00 -> 1.00)

Sanel Zukan

unread,
Nov 2, 2014, 12:12:21 PM11/2/14
to Remy Oukaour, fltkg...@googlegroups.com
Hi,

On Linux, assuming you are running composite manager, setting
transparency should not be that hard: just set window property using
_NET_WM_WINDOW_OPACITY atom with opacity level.

Here is a snipet from EDE:

...
Atom atom = XInternAtom(fl_display, "_NET_WM_WINDOW_OPACITY", False);
uint opacity = 0xc0000000;
XChangeProperty(fl_display, fl_xid(window),
atom, XA_CARDINAL, 32, PropModeReplace,
(unsigned char*)&opacity, 1L);
...

where 'window' is Fl_Window or Fl_Double_Window object.

Best,
Sanel

Albrecht Schlosser

unread,
Nov 2, 2014, 7:54:09 PM11/2/14
to fltkg...@googlegroups.com
On 02.11.2014 18:12, Sanel Zukan wrote:

> On Linux, assuming you are running composite manager,

Do we need to check this, or does the code below work anyway, because
the window manager will ignore the request?

> setting
> transparency should not be that hard: just set window property using
> _NET_WM_WINDOW_OPACITY atom with opacity level.
>
> Here is a snipet from EDE:
>
> ...
> Atom atom = XInternAtom(fl_display, "_NET_WM_WINDOW_OPACITY", False);
> uint opacity = 0xc0000000;
> XChangeProperty(fl_display, fl_xid(window),
> atom, XA_CARDINAL, 32, PropModeReplace,
> (unsigned char*)&opacity, 1L);
> ...
>
> where 'window' is Fl_Window or Fl_Double_Window object.

Yes, this doesn't look very complicated.

Do you know what the value 0xc0000000 is? Is this the alpha value? How
is it calculated? Looks like 75%, maybe...

Thanks for the code. I g****ed for docs, but could only find "proposols"
and similar. Do you have a link?

Remy Oukaour

unread,
Nov 2, 2014, 11:00:34 PM11/2/14
to fltkg...@googlegroups.com
Sanel, thank you for your solution.

I found somewhere else that the general formula is:
uint32_t opacity = (uint32_t)(UINT32_MAX * alpha);
where alpha ranges from 0 to 1.

So here's the final callback function:

void Fl_Window::set_transparency(float alpha) {
#if defined(_WIN32)
    HWND hwnd = fl_xid(this);

    LONG_PTR exstyle = GetWindowLongPtr(hwnd, GWL_EXSTYLE);
    if (!(exstyle & WS_EX_LAYERED)) {
        SetWindowLongPtr(hwnd, GWL_EXSTYLE, exstyle | WS_EX_LAYERED);
    }
    SetLayeredWindowAttributes(hwnd, 0, (BYTE)(alpha * 0xFF), LWA_ALPHA);
#elif defined(__APPLE__)
    setWindowTransparency(this, alpha); // definition in previous post
#elif defined(__linux__) || defined(__unix__) // standard way to check for *nix?

    Atom atom = XInternAtom(fl_display, "_NET_WM_WINDOW_OPACITY", False);
    uint32_t opacity = (uint32_t)(UINT32_MAX * alpha);
    XChangeProperty(fl_display, fl_xid(this), atom, XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&opacity, 1);
#else
    // Transparency only supported on Microsoft Windows, Mac OS X, and Linux with X11
#endif
}

I've tested this on Windows 8.1, Mac OS X 10.9, and Xubuntu 14.04, and it makes the main window transparent. I don't know if it would work for widgets in general.

Sanel Zukan

unread,
Nov 3, 2014, 2:58:36 AM11/3/14
to fltkg...@googlegroups.com
On 11/03/14,Albrecht Schlosser wrote:
> Do we need to check this, or does the code below work anyway, because
> the window manager will ignore the request?

No need to check for this; WM will ignore it anyway and composite
manager will pick it up when is running.

> > setting
> > transparency should not be that hard: just set window property using
> > _NET_WM_WINDOW_OPACITY atom with opacity level.
> >
> > Here is a snipet from EDE:
> >
> > ...
> > Atom atom = XInternAtom(fl_display, "_NET_WM_WINDOW_OPACITY",
> > False); uint opacity = 0xc0000000;
> > XChangeProperty(fl_display, fl_xid(window),
> > atom, XA_CARDINAL, 32, PropModeReplace,
> > (unsigned char*)&opacity, 1L);
> > ...
> >
> > where 'window' is Fl_Window or Fl_Double_Window object.
>
> Yes, this doesn't look very complicated.
>
> Do you know what the value 0xc0000000 is? Is this the alpha value?
> How is it calculated? Looks like 75%, maybe...

You can calculate the value like this:

0.80 * 0xffffffff = the window is 80% opaque (or 20% transparent)

but general guideline is that transparency range is 0 - 0xffffffff
(where 0 is fully transparent).

> Thanks for the code. I g****ed for docs, but could only find
> "proposols" and similar. Do you have a link?

Gah, that is the problem with freedesktop community: things got
implemented without notice. The best document is to check gtk source
(gdkwindow-x11.c), demos like https://gist.github.com/chjj/1342484 or
to dig inside composite manager code, like for xcompmgr.

Not sure why this didn't get in official specification.

Also, you might be interested in _NET_WM_OPAQUE_REGION
(http://standards.freedesktop.org/wm-spec/wm-spec-latest.html) for
setting transparent regions inside window. Gtk is using this under
'gdk_x11_window_set_opaque_region()' function.

Mess, I know...

Best,
Sanel

Kevin Ingwersen (Ingwie Phoenix)

unread,
Nov 3, 2014, 7:46:23 PM11/3/14
to fltkg...@googlegroups.com
--
You received this message because you are subscribed to the Google Groups "fltk.general" group.
To unsubscribe from this group and stop receiving emails from it, send an email to fltkgeneral...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

That’s awesome! 1.3.3 is out, and new features are already in the pipeline…that is pretty nice.
setWindowTransparency() could be defined within Fl_cocoa.mm since its Objective-C. I’ll test this functionality later on OS X 10.10 to see if it works here too.

MacArthur, Ian (Selex ES, UK)

unread,
Nov 4, 2014, 4:56:53 AM11/4/14
to fltkg...@googlegroups.com
> On 11/01/14 16:37, Remy Oukaour wrote:
> > Okay, I figured out how to do this in OS X. Here's the callback:
> > [good info snipped]
> > Hopefully this will help anyone else writing cross-platform apps.
>
> I'd like to think we can merge this into the API at some point,
> perhaps after the 1.3.3 release goes out in the next few days.
>
> If we can get consensus from the devs, it can be added.

If for one think this would be a cool feature to have.

Though, that said, I seldom actually use transparency in windows myself...!


Selex ES Ltd
Registered Office: Sigma House, Christopher Martin Road, Basildon, Essex SS14 3EL
A company registered in England & Wales. Company no. 02426132
********************************************************************
This email and any attachments are confidential to the intended
recipient and may also be privileged. If you are not the intended
recipient please delete it from your system and notify the sender.
You should not copy it or use it for any purpose nor disclose or
distribute its contents to any other person.
********************************************************************

MacArthur, Ian (Selex ES, UK)

unread,
Nov 4, 2014, 5:12:02 AM11/4/14
to fltkg...@googlegroups.com
Hi Remy,

This seems like a cool feature, thanks.


> I found somewhere else that the general formula is:
> uint32_t opacity = (uint32_t)(UINT32_MAX * alpha);
> where alpha ranges from 0 to 1.

Yup, that's essentially what Sanel has, so that seems like we have a consistent solution.



> #elif defined(__linux__) || defined(__unix__)
> // standard way to check for *nix?

Well, actually, what we usually do is let it fall through, on the basis that if it is *not* Win32 and it is *not* Apple then it "must be" some sort of *nix system, or at any rate a system running X11.

However:

Note that in this case, the "interesting thing" probably is not whether it is a *nix system, but whether it is running X11.

Note that both the Win32 and OSX builds can support X11 as an alternate to their native graphics layer (indeed I think the Cygwin default builds for X11 these days? I don't use it anymore, just mingw now.)

So I guess ideally we'd need to figure out if we have X11 in any form, including X11/Win32 and X11/OSX, and use the "X11 path" in all those cases, then fall back to using the native Win32 and Apple code in the other "normal" cases?


I imagine our code must be doing this in places already - I know that the XFT code (which we only use with X11) has some Cygwin specific elements for Win32 builds, so there must be some detection / selection going on there (perhaps in configure though? Dunno now...)

Manolo Gouy

unread,
Nov 4, 2014, 6:59:40 AM11/4/14
to fltkg...@googlegroups.com

> Note that in this case, the "interesting thing" probably is not whether it is a *nix system, but whether it is running X11.
>
> Note that both the Win32 and OSX builds can support X11 as an alternate to their native graphics layer (indeed I think the Cygwin default builds for X11 these days? I don't use it anymore, just mingw now.)
>
> So I guess ideally we'd need to figure out if we have X11 in any form, including X11/Win32 and X11/OSX, and use the "X11 path" in all those cases, then fall back to using the native Win32 and Apple code in the other "normal" cases?
>
>
> I imagine our code must be doing this in places already - I know that the XFT code (which we only use with X11) has some Cygwin specific elements for Win32 builds, so there must be some detection / selection going on there (perhaps in configure though? Dunno now...)

Id like to use this message as an opportunity to clarify whether and how the X11 system is
usable by FLTK under Mac OS X.

The present FLTK code can be compiled (and run) on a mac to use X11 windows (instead of cocoa) with just two steps:
- define USE_X11 in file config.h
- add
-U__APPLE__ -I/opt/X11/include -I/opt/X11/include/freetype2
to all compilation commands (or do the equivalent in Xcode)

In addition, it’s required to install X11 support on the mac by downloading the XQuartz package from
http://xquartz.macosforge.org/landing/

In the code itself, windowing system-specific sections should be (and currently are) organized as follows:
#include <config.h> // it defines USE_X11 if appropriate

#if defined(USE_X11)
…. Xlib-Using code
#elif defined(WIN32)
…. MSWindows code
#elif defined(__APPLE__)
…. cocoa code
#else
# error unsupported platform
#endif

israel dahl

unread,
Aug 10, 2018, 8:13:23 AM8/10/18
to fltk.general
To clarify how I ended up solving this issue:
I used X11 to get the color of a pixel under the area where I am going to draw, and set the background to that pixel color
XImage *image;
 image
= XGetImage (fl_display,RootWindow (fl_display, DefaultScreen (fl_display)),
  x
, y, 1, 1, AllPlanes, XYPixmap);
  c
.pixel = XGetPixel (image, 0, 0);
 
XFree (image);
 
//TODO
 
XQueryColor (fl_display,DefaultColormap(fl_display, DefaultScreen (fl_display)), &c);
 
unsigned int BGColor=get_fl_color(&c);
  client
->color(BGColor);
  client
->redraw();

This works well for me since I am only targeting X11 environments.
Reply all
Reply to author
Forward
0 new messages