Problems with window decorations in 64-bit Linux


#1

Hello!

When using Juce on 64-bit Linux the native window decorations don’t work correctly. Depending on the window manager used and the settings you implement in the Juce application (setUsingNativeTitleBar), you either have no title bar at all, or a native title bar and window borders, that don’t allow you to resize or Juce’s title bar and resize borders and additional the native ones…
There was already a thread in this forum “Linking with Release library causes native window decoration”.

I investigated that further and to my opinion the problem is in the interface to the X functions XGetWindowProperty and XChangeProperty. The X documentation says, that if you specify 32 as format you have to pass a pointer to one or more long’s or receive values that are represented as long’s. This even holds when used on 64-bit Linux, where the long is a 64-bit value. This is really weird in the X interface, but so it is.

I found, that in “juce_linux_Windowing.cpp” for most calls 32-bit values are passed to or expected from these X functions. That also works in 64-bit linux with little endian architecture as long as only one value is passed in or received. But it does not work, if multiple values are passed in a call.

I changed all datatypes, that are passed as data to XChangeProperty and that are received as data from XGetWindowProperty to long data types. Now my application behaves as before on 32-bit Linux and now the same on 64-bit Linux. But I have to admit, that I only tested the case of switching the native title bar on and off. I don’t know, if this change has other side effects.
Since this is a number of small changes in the file, here is the output of a “svn diff” before committing the change into my local Subversion repository:

[code]
Index: juce_linux_Windowing.cpp

— juce_linux_Windowing.cpp (Revision 204)
+++ juce_linux_Windowing.cpp (Arbeitskopie)
@@ -107,7 +107,7 @@
static Atom wm_ChangeState = None;
static Atom wm_State = None;
static Atom wm_Protocols = None;
-static Atom wm_ProtocolList [2] = { None, None };
+static unsigned long wm_ProtocolList [2] = { None, None };
static Atom wm_ActiveWin = None;

#define ourDndVersion 3
@@ -859,7 +859,7 @@
&& actualFormat == 32
&& nitems > 0)
{

  •        if (((CARD32*) stateProp)[0] == IconicState)
    
  •        if (((unsigned long*) stateProp)[0] == IconicState)
               minimised = true;
    
           XFree (stateProp);
    

@@ -1651,7 +1651,7 @@
}

     // For older KDE's ...
  •    int atomData = 1;
    
  •    long atomData = 1;
       Atom trayAtom = XInternAtom (display, "KWM_DOCKWINDOW", false);
       XChangeProperty (display, windowH, trayAtom, trayAtom, 32, PropModeReplace, (unsigned char*) &atomData, 1);
    

@@ -1810,14 +1810,15 @@
{
typedef struct
{

  •            CARD32 flags;
    
  •            CARD32 functions;
    
  •            CARD32 decorations;
    
  •            INT32 input_mode;
    
  •            CARD32 status;
    
  •            unsigned long flags;
    
  •            unsigned long functions;
    
  •            unsigned long decorations;
    
  •            long input_mode;
    
  •            unsigned long status;
           } MotifWmHints;
    
           MotifWmHints motifHints;
    
  •        memset(&motifHints, 0, sizeof(motifHints));
           motifHints.flags = 2; /* MWM_HINTS_DECORATIONS */
           motifHints.decorations = 0;
    

@@ -1849,7 +1850,7 @@

     if (hints != None)
     {
  •        Atom netHints [2];
    
  •        unsigned long netHints [2];
           netHints[0] = XInternAtom (display, "_KDE_NET_WM_WINDOW_TYPE_OVERRIDE", True);
    
           if ((styleFlags & windowIsTemporary) != 0)
    

@@ -1870,15 +1871,15 @@
{
typedef struct
{

  •            CARD32 flags;
    
  •            CARD32 functions;
    
  •            CARD32 decorations;
    
  •            INT32 input_mode;
    
  •            CARD32 status;
    
  •            unsigned long flags;
    
  •            unsigned long functions;
    
  •            unsigned long decorations;
    
  •            long input_mode;
    
  •            unsigned long status;
           } MotifWmHints;
    
           MotifWmHints motifHints;
    
  •        memset(&motifHints, 0, sizeof(motifHints));
           motifHints.flags = 1 | 2; /* MWM_HINTS_FUNCTIONS | MWM_HINTS_DECORATIONS */
           motifHints.decorations = 2 /* MWM_DECOR_BORDER */ | 8 /* MWM_DECOR_TITLE */ | 16; /* MWM_DECOR_MENU */
    

@@ -1912,7 +1913,7 @@

     if (hints != None)
     {
  •        Atom netHints [6];
    
  •        unsigned long netHints [6];
           int num = 0;
    
           netHints [num++] = XInternAtom (display, "_NET_WM_ACTION_RESIZE", (styleFlags & windowIsResizable) ? True : False);
    

@@ -2080,7 +2081,7 @@
XChangeProperty (display, wndH, XA_XdndActionDescription, XA_STRING, 8, PropModeReplace,
(const unsigned char*) “”, 0);

  •    uint32 dndVersion = ourDndVersion;
    
  •    unsigned long dndVersion = ourDndVersion;
       XChangeProperty (display, wndH, XA_XdndAware, XA_ATOM, 32, PropModeReplace,
                        (const unsigned char*) &dndVersion, 1);
    

@@ -2186,7 +2187,7 @@
XA_CARDINAL, &actualType, &actualFormat, &nitems, &bytesLeft,
&data) == Success)
{

  •                const CARD32* const sizes = (const CARD32*) data;
    
  •                const unsigned long* const sizes = (const unsigned long*) data;
    
                   if (actualFormat == 32)
                       windowBorder = BorderSize ((int) sizes[2], (int) sizes[0],
    

@@ -2364,7 +2365,7 @@
{
if (actual == XA_ATOM && format == 32 && count != 0)
{

  •                const Atom* const types = (const Atom*) data;
    
  •                const unsigned long* const types = (const unsigned long*) data;
    
                   for (unsigned int i = 0; i < count; ++i)
                       if (types[i] != None)
    

@@ -2466,8 +2467,8 @@
Atom XA_OtherMime, dragAndDropCurrentMimeType;
Window dragAndDropSourceWindow;

  • Atom allowedActions [5];
  • Atom allowedMimeTypeAtoms [3];
  • unsigned long allowedActions [5];
  • unsigned long allowedMimeTypeAtoms [3];
    Array srcMimeTypeAtomList;
    };

Regards,
Andreas[/code]


#2

Thanks for that andreas! I’ll take your word for that fact that it works, as I’ve only got 32-bit machines to test it on.


#3

I re-checked it and tested also other functions like “ResizableWindow::setResizable” and “DocumentWindow::setTitleBarButtonsRequired” with various combinations of buttons (and using “TopLevelWindow::setUsingNativeTitleBar(true)”). That all works now with 64-bit Linux as well as with 32-bit Linux. Whereas before it was very indeterministic on 64-bit Linux.

Only a “ResizableWindow::setResizable(false)” does not work sometimes, but that depends on the X window manager used (some seem to ignore that) and not on 32- or 64-bit.


#4

I checked the adoption of this fix in the current version of the Juce subversion repository, and I think you missed a few instances:

109c109
< static Atom wm_ProtocolList [2] = { None, None };
---
> static unsigned long wm_ProtocolList [2] = { None, None };

....

1814c1814
<                 ::INT32 input_mode;
---
>                 long input_mode;

....

1875c1875
<                 ::INT32 input_mode;
---
>                 long input_mode;

....

2189c2189
<                     const unsigned long* const sizes = (const CARD32*) data;
---
>                     const unsigned long* const sizes = (const unsigned long*) data;

#5

ok, thanks!


#6

What eventually it is necessary to it?


#7

Sorry, no idea what you’re asking!