Updating program to 1.4.x

48 views
Skip to first unread message

Rob McDonald

unread,
May 24, 2021, 2:41:03 PM5/24/21
to fltk.general
I am in the process of updating my program to work with the 1.4 branch (specifically  working from commit cbee4880f45c).  I've been on the 1.3 branch happily, and am finally testing the 1.4 waters...

There are a handful of things that have popped up so far.

In at least one case so far, 1.4 is more sensitive to a bug in our use of it, so it is helping us find some problems.

I have an extension of Fl_Button to support drag-n-drop.  I do this...

int MyButton::handle(int event)
{
  int ret = Fl_Button::handle(event);
  switch ( event ) {
    case FL_DRAG:
      if( callback() )
      {
        do_callback();
      }
      ret = 1;
      break;

    default:
      break;
  }
  return ret;
}


So the Fl_Button do_callback() is wired up 

Rob McDonald

unread,
May 24, 2021, 2:47:55 PM5/24/21
to fltk.general
Sorry, posted before I was done writing the message...

So the Fl_Button do_callback() is wired up to capture FL_DRAG.  The callback gets passed along to my class that contains the pointer to the MyButton...  We'll call that a ButtonHolder.  It handles the event with this code...

void ButtonHolder::DeviceCB( Fl_Widget* w )
{
  if ( w == m_Button ) // m_Button is the pointer to the MyButton
  {
    switch ( Fl::event() ) {
      case FL_DRAG:
        Fl::copy( m_Foo.c_str(), m_Foo.size(), 0 );
        Fl::dnd();

        break;

      case FL_RELEASE:
        if( Fl::event_inside( w ) )
        {
          // Do something else.
        }

        break;

      default:
        break;
    }
  }
}
 

The problem is -- every time a FL_DRAG event is started, the FL_RELEASE event immediately triggers (even before a button release).  This only happens on MacOS, it does not happen on Windows.  This code worked fine on 1.3.X.

Any ideas why Clicking and holding (drag hasn't even started) on MacOS would trigger a Release event?

Thanks,

Rob

Ian MacArthur

unread,
May 24, 2021, 5:26:11 PM5/24/21
to fltkg...@googlegroups.com
Can you put together a minimal (complete) example that shows the behaviour?
I’m having trouble putting it all together in my head...

Like... when exactly does DeviceCB() get called, and why does it call Fl::event() rather than, say, being passed the current event of interest? In particular I’m concerned that what Fl::event() is returning here might not actually be the event of interest, if it is being called in the wrong context, say...

Or something else.


Rob McDonald

unread,
May 24, 2021, 6:02:16 PM5/24/21
to fltk.general
I can try, but it isn't going to be easy...

Is there a MWE of drag-n-drop that I could start from -- it is probably easier to start there and extend a Fl_Button to be the origin of the payload rather than start from my program and strip it down.... (hopefully it would show the same odd behavior).

My program uses a bunch of classes that hold Fl_Widgets -- duplicating all that in a MWE is not going to be small or clear...

I'm generally confident in what we're doing -- it has worked fine for about a decade.

In the short term, if you have the time and desire to dig deeper, I'll try to present a guide through the real code with the parts I omitted the first time filled in....

1 The over-ridden Fl_Button::handle is implemented here as VspButton.
2 The wrapper class that contains the over-ridden Fl_Button is defined here, it is ParmButton.
3 That wrapper is an extension of a base wrapper class defined here, it is a GuiDevice.
4 When the wrapper is set up, the Fl_Button::callback() method is called here in ParmButton::Init().  Which references GuiDevice::StaticDeviceCB, which always turns around and calls the class's DeviceCB.
5 The ParmButton's DeviceCB is the other bit that implements the callback here.

This is how I handle 'low-level' events.  These are typically fairly universal behavior throughout the program.

My original email summarized only steps 1 & 5.  Hopefully 2-4 help answer your question.

A bunch of GuiDevices are typically associated with a Screen.  That screen is where the developer usually does most of their GUI work including a callback for the entire screen.  This is where unique behavior of individual buttons is implemented.

Higher level events are passed to m_Screen->GuiDeviceCallBack() as the last line of the ParmButton::DeviceCB.  

Rob

Greg Ercolano

unread,
May 24, 2021, 7:00:09 PM5/24/21
to fltkg...@googlegroups.com

On 5/24/21 3:02 PM, Rob McDonald wrote:

I can try, but it isn't going to be easy...
Is there a MWE (*) of drag-n-drop that I could start from [..]

    In 1.4.x there's examples/howto-drag-and-drop.cxx


(*) Minimum Working Example, for those wondering..

Rob McDonald

unread,
May 24, 2021, 9:19:17 PM5/24/21
to fltk.general
Thanks.

I had just pulled the example from your cheat sheet and was starting to work from that.  This looks to be a bit nicer over all.

Rob

Rob McDonald

unread,
May 24, 2021, 9:38:55 PM5/24/21
to fltk.general
Thanks Greg,

I've attached a MWE of this issue below.  I tried to make the minimum changes to Greg's example, so it doesn't match my situation 100%, but it does show the unexpected (to me) behavior.

Observed behavior --
fl_choice "You Pushed the Button!" displayed on button press (not release).  Even when initiating a drag-n-drop to a target.
Drag-n-drop still works as desired

Desired behavior - 
fl_choice Not displayed when initiating a drag-n-drop operation.
fl_choice Only displayed when button is released and mouse is still within the button extents
Nothing happens if you click on the button, drag outside the button, and release outside the drop target.

I'm on MacOS Catalina 10.15.7 -- with all updates.

FLTK 1.4.x from cbee4880f45c on GitHub.

'c++ --version' Reports:
Apple clang version 12.0.0 (clang-1200.0.32.29)
Target: x86_64-apple-darwin19.6.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin

Rob
dnd-issue.cxx

Manolo

unread,
May 25, 2021, 4:32:16 AM5/25/21
to fltk.general
I see that the macOS version of the D-n-D code sends an FL_RELEASE event right after the initial FL_DRAG event,
while the Windows versions sends it after the end of the D-n-D operation. That part of the code is unchanged
between 1.3 and 1.4. Some more analysis is required to determine whether this FL_RELEASE event is wrong
or not. In the meantime, I suggest you modify a bit your handle() function as in the attached code to have it process
the FL_RELEASE event only after the end of a D-n-D operation. With this change, the test program is correct
both under macOS and Windows.
repair.cxx.txt

Albrecht Schlosser

unread,
May 25, 2021, 7:01:03 AM5/25/21
to fltkg...@googlegroups.com
On 5/25/21 10:32 AM Manolo wrote:
I see that the macOS version of the D-n-D code sends an FL_RELEASE event right after the initial FL_DRAG event,
while the Windows versions sends it after the end of the D-n-D operation. ... Some more analysis is required to determine whether this FL_RELEASE event is wrong or not.

Hi Manolo,

just from reading your words (above) I would assume that sending FL_RELEASE while doing the DND operation is actually wrong and unexpected behavior because the mouse button is still held down until ... the drop occurs by releasing the mouse button. This is the point where FL_RELEASE should be sent.

That said, the docs state:

  FL_DND_RELEASE

  The user has released the mouse button dropping data into the widget.

(end of citation)

The docs don't explicitly state that an FL_RELEASE event is also sent, but I think this is necessary for apps not watching FL_DND_* events.


Rob McDonald

unread,
May 25, 2021, 12:46:35 PM5/25/21
to fltk.general
Manolo - thanks for the help on this.

Curious that the 1.3.x code reads wrong, but seemed to work properly -- while the 1.4.x code is behaving in a way that matches the code.  There must be some other code in some other region that is changing the observed behavior.

What is the difference in what initiates an FL_DRAG vs. FL_PUSH event?  For example, what will happen if a user clicks and releases the button -- without ever moving the mouse a single pixel while the button is pressed.

In my mind, that should trigger a FL_PUSH, but not a FL_DRAG event.  So, the way I read your suggested fix, it should fail for a push-but-not-drag event.

In practice, I can get your version to behave in three ways...

Quick press-and-release of button without movement -- fl_choice() window does not get displayed (broken)
Quick press-and-release of button with imperceptible movement (mouse icon does not change to truck) -- fl_choice() window is displayed 
Press-drag-and-release of button (staying within button bounds), mouse icon changes to truck, - fl_choice() window does not get displayed (broken)

Rob 

Ian MacArthur

unread,
May 25, 2021, 3:29:12 PM5/25/21
to fltkg...@googlegroups.com
So I took Rob’s example and added FL/names.h to it, replaced the fl_choice with a printf and compiled it with 1.3 and 1.4. There is a difference...

Looking at the events in the Sender, with 1.3, I see basically:

FL_MOVE : 0
FL_MOVE : 0
FL_MOVE : 0
FL_FOCUS : 1
FL_PUSH : 1
FL_DRAG : 1
FL_DND_DRAG : 0
FL_DND_DRAG : 0
:
FL_DND_DRAG : 0
FL_DND_DRAG : 0
FL_DND_LEAVE : 0
FL_DND_LEAVE : 0
FL_RELEASE : 1
You Pushed the Button!
FL_ENTER : 1
FL_MOVE : 0
FL_MOVE : 0

With 1.4 I get:

FL_MOVE : 0
FL_FOCUS : 1
FL_PUSH : 1
FL_DRAG : 1
FL_RELEASE : 1
You Pushed the Button!
FL_DND_DRAG : 0
FL_DND_DRAG : 0
FL_DND_DRAG : 0


It’s pretty consistent. 1.4 is seeing the FL_RELEASE before the FL_DND_DRAG, whereas 1.3 does not.
I do not know why this is happening...



Manolo

unread,
May 26, 2021, 2:35:58 AM5/26/21
to fltk.general
I confirm that, at least in my hands on macOS 11.3, FLTK 1.3 and 1.4 behave identically when dragging.
That's expected, I believe, because the underlying source code is identical in the 2 branches.

Ian MacArthur

unread,
May 26, 2021, 5:04:00 AM5/26/21
to fltk.general
On Wednesday, 26 May 2021 at 07:35:58 UTC+1 Manolo wrote:
I confirm that, at least in my hands on macOS 11.3, FLTK 1.3 and 1.4 behave identically when dragging.
That's expected, I believe, because the underlying source code is identical in the 2 branches.

Hmmm... My Mac is old, so still on 10.13.6 (IIRC) and, as shown in the capture I posted yesterday, I see a different stream of events in the 1.3 compiled version vs. the 1.4 version.

I'll check again (later today) and post again. (Not on the Mac just now...)

In the meantime, here's the code I used for my test, in case I did something awry.
It's basically Rob's code but with fl_eventnames output added to the Sender handle() so we can see what is going on a bit more clearly.

//
// A simple demo of 'drag and drop' with FLTK.
// Originally from erco's cheat sheet, permission by author.
// Inspired by Michael Sephton's original example posted on fltk.general.
//
// When you run the program, just drag the red square over
// to the green square to show a 'drag and drop' sequence.
//
// You can also drag and drop text from another application over
// to the green square to show a 'drag and drop' sequence.
//
// Copyright 1998-2017 by Bill Spitzak and others.
//
// This library is free software. Distribution and use rights are outlined in
// the file "COPYING" which should have been included with this file.  If this
// file is missing or damaged, see the license at:
//
//
// Please see the following page on how to report bugs and issues:
//
//

#include <stdio.h>
#include <FL/Fl.H>
#include <FL/Fl_Window.H>
#include <FL/Fl_Box.H>
#include <FL/Fl_Button.H>
#include <FL/fl_ask.H> // fl_message()

#include <FL/names.h> // fl_eventnames[]

// SIMPLE SENDER CLASS
class Sender : public Fl_Button {
public:
  // Ctor
  Sender(int x,int y,int w,int h, const char *label = 0) : Fl_Button(x,y,w,h,label) {
  }

  // Sender event handler
  int handle(int event) {
    int ret = Fl_Button::handle(event);

    printf ("%s : %d\n", fl_eventnames[event], ret); fflush(stdout);

    switch ( event ) {
      case FL_DRAG: {             // do 'copy/dnd' when someone clicks on box
        const char *msg = "It works!";
        Fl::copy(msg,strlen(msg),0);
        Fl::dnd();
        ret = 1;
        break;
      }
      case FL_RELEASE: {
        if( Fl::event_inside( this ) ) {
          // fl_choice("You Pushed the Button!", "Ok", 0, 0);
          printf ("You Pushed the Button!\n"); fflush(stdout);
          ret = 1;
        }
        break;
      }
    }
    return(ret);
  }
};
// SIMPLE RECEIVER CLASS
class Receiver : public Fl_Box {
  int dnd_inside;
  char *dnd_text;
public:
  // Ctor
  Receiver(int x,int y,int w,int h) : Fl_Box(x,y,w,h) {
    box(FL_FLAT_BOX); color(10); label("..to\nhere");
    dnd_inside = 0;
    dnd_text = 0;
  }
  // Receiver event handler
  int handle(int event) {
    int ret = Fl_Box::handle(event);
    int len;
    switch ( event ) {
      case FL_DND_ENTER:        // return(1) for this event to 'accept' dnd
        label("ENTER");         // visible only if you stop the mouse at the widget's border
        fprintf(stderr, "FL_DND_ENTER\n");
        dnd_inside = 1;         // status: inside the widget, accept drop
        ret = 1;
        break;
      case FL_DND_DRAG:         // return(1) for this event to 'accept' dnd
        label("drop\nhere");
        fprintf(stderr, "FL_DND_DRAG\n");
        ret = 1;
        break;
      case FL_DND_RELEASE:      // return(1) for this event to 'accept' the payload (drop)
        fprintf(stderr, "FL_DND_RELEASE\n");
        if (dnd_inside) {
          ret = 1;              // return(1) and expect FL_PASTE event to follow
          label("RELEASE");
        } else {
          ret = 0;              // return(0) to reject the DND payload (drop)
          label("DND\nREJECTED!");
        }
        break;
      case FL_PASTE:              // handle actual drop (paste) operation
        fprintf(stderr, "FL_PASTE\n");
        copy_label(Fl::event_text());
        fprintf(stderr, "Pasted '%s'\n", Fl::event_text());

        // Don't pop up dialog windows in FL_DND_* or FL_PASTE event handling
        // resulting from DND operations. This may hang or even crash the
        // application on *some* platforms. Use a short timer to delay the
        // message display after the event processing is completed.

        delete[] dnd_text;      // don't leak (just in case)
        dnd_text = 0;

        len = Fl::event_length();
        if (len && Fl::event_text()) {
          dnd_text = new char[len + 1];
          memcpy(dnd_text, Fl::event_text(), len);
          dnd_text[len] = '\0';
          Fl::add_timeout(0.001, timer_cb, this); // delay message popup
        }
        ret = 1;
        break;
      case FL_DND_LEAVE:        // not strictly necessary to return(1) for this event
        label("..to\nhere");    // reset label
        fprintf(stderr, "FL_DND_LEAVE\n");
        dnd_inside = 0;         // status: mouse is outside, don't accept drop
        ret = 1;                // return(1) anyway..
        break;
    }
    return(ret);
  }

  // static timer callback
  static void timer_cb(void *data) {
    Receiver *r = (Receiver *)data;
    r->dnd_cb();
  }

  // dnd (FL_PASTE) popup method
  void dnd_cb() {
    if (dnd_text) {
      fl_message("%s", dnd_text);
      delete[] dnd_text;
      dnd_text = 0;
    }
  }
};

int main(int argc, char **argv) {
  // Create sender window and widget
  Fl_Window win_a(0,0,200,100,"Sender");
  Sender a(0,0,100,100, "Drag or Push");
  win_a.end();
  win_a.show();
  // Create receiver window and widget
  Fl_Window win_b(400,0,200,100,"Receiver");
  Receiver b(100,0,100,100);
  win_b.end();
  win_b.show();
  return(Fl::run());
}

/* end of file */

 

Ian MacArthur

unread,
May 26, 2021, 6:15:45 AM5/26/21
to fltk.general
On Wednesday, 26 May 2021 at 10:04:00 UTC+1 Ian MacArthur 

I'll check again (later today) and post again. (Not on the Mac just now...)

Well, that was interesting... coffee break, so I went through to the Mac and gave it a spin.

If I use my "production" version of 1.3 (which is basically an early 1.3.5 candidate I froze for consistency) I get the sequence of events noted earlier - Rob's "working" sequence.

With either 1.4, or the 1.3.6 snapshot from git, I get the "failing" sequence.

So the change here is not in 1.4 per se, but somewhere in the 1.3.5 -> 1.3.6 progression.

That may also explain why Rob sees this effect; I'd guess he is using an older "stable"  version of 1.3.x for the bulk of his work?

Rob, can you give 1.3.6 a try to see if it also "fails" for you or not?



Rob McDonald

unread,
May 26, 2021, 11:49:47 AM5/26/21
to fltk.general
On Wednesday, May 26, 2021 at 3:15:45 AM UTC-7 Ian MacArthur wrote:
That may also explain why Rob sees this effect; I'd guess he is using an older "stable"  version of 1.3.x for the bulk of his work?

Rob, can you give 1.3.6 a try to see if it also "fails" for you or not?

I'll see what I can do.

You are correct, I've been on 1.3.5 for a long time -- was looking to go to 1.3.6, but decided to go to 1.4.x to get all the other stuff that goes with it while I was at it.

Sorry for being vague about which version was showing the 'working' behavior -- I assumed it was in the 'bigger' jump.

Rob


 

Rob McDonald

unread,
May 26, 2021, 12:59:18 PM5/26/21
to fltk.general
Bad versions:
1.3.6 Release appears to behave the same as 1.4.x
0c70362e63d6 behaves the same as 1.4.x (I was actually on this version and hadn't noticed the problem).

Good versions:
1.3.5 Release behaves as I expect and desire.
1.3.4-2 Builds, but graphics do not display on this new of MacOS
1.3.3 Will not build cleanly with this new of OS / compiler
1.3.2 Will not build cleanly with this new of OS / compiler - Version used when DND feature was introduced to my application

Rob
 
 

Rob McDonald

unread,
May 26, 2021, 5:59:14 PM5/26/21
to fltk.general
Bad versions:
1.3.6 Release appears to behave the same as 1.4.x
0c70362e63d6 behaves the same as 1.4.x (I was actually on this version and hadn't noticed the problem).

Good versions:
1.3.5 Release behaves as I expect and desire.
1.3.4-2 Builds, but graphics do not display on this new of MacOS
1.3.3 Will not build cleanly with this new of OS / compiler
1.3.2 Will not build cleanly with this new of OS / compiler - Version used when DND feature was introduced to my application

Since there really aren't very many changes between 1.3.5 and 1.3.6, I did a little manual bisecting to see if I could help narrow the search.

There were two (groups) of commits that looked like possible culprits.

The regression was introduced in:

46235ff92216   Transfer to branch 1.3 all changes in Fl_cocoa.mm from branch 1.4 as of 20 may 2020

Unfortunately, as you might guess from the commit message, it is a pretty big commit with a wholesale group of changes in it.  I scanned through the commit and nothing jumped out at me -- but I am totally unfamiliar with FLTK code at this level.

It might be possible to do a better job bisecting this on the 1.4 branch -- where the changes were most likely implemented in a more fine grained way.

Rob



 

Albrecht Schlosser

unread,
May 26, 2021, 6:10:19 PM5/26/21
to fltkg...@googlegroups.com
On 5/26/21 11:59 PM Rob McDonald wrote:
Bad versions:
1.3.6 Release appears to behave the same as 1.4.x

Good versions:
1.3.5 Release behaves as I expect and desire.
Since there really aren't very many changes between 1.3.5 and 1.3.6, I did a little manual bisecting to see if I could help narrow the search.

Thanks for your help finding the issue.


The regression was introduced in:

46235ff92216   Transfer to branch 1.3 all changes in Fl_cocoa.mm from branch 1.4 as of 20 may 2020

From all I read so far I agree that this is a bug and a regression in 1.3.6 which means that we need to release yet another 1.3.x version.


It might be possible to do a better job bisecting this on the 1.4 branch -- where the changes were most likely implemented in a more fine grained way.

Since 1.4 has not been released yet there's no pressure with 1.4, but it would be a good opportunity to bisect the commits, as you say. I assume that Manolo is already working on it behind the scenes. I hope that he can figure out what happened and hopefully resolve this.

Manolo

unread,
May 27, 2021, 2:51:56 AM5/27/21
to fltk.general
The premature sending of an FL_RELEASE event should be fixed now both in the 1.4 and 1.3 branches.

Albrecht Schlosser

unread,
May 27, 2021, 8:05:06 AM5/27/21
to fltkg...@googlegroups.com
On 5/27/21 8:51 AM Manolo wrote:
> The premature sending of an FL_RELEASE event should be fixed now both
> in the 1.4 and 1.3 branches.

Thank you very much!

I'll schedule a new 1.3.x release as soon as this has been confirmed by
Rob, proven stable, and time permits.

@Rob: Could you please test with your application linked against both
1.3.6+ (Git, with this update), and 1.4.x (Git or next snapshot
tomorrow) and confirm that this fixes your problem?

Rob McDonald

unread,
May 27, 2021, 11:07:49 AM5/27/21
to fltk.general
I tested the following:

47ba6632b1be -- Tip of master
371eb6565494 -- Tip of branch-1.3

Both worked great!

Thanks Manolo, Albrecht, & Greg.

Rob


 

Albrecht Schlosser

unread,
May 27, 2021, 11:32:55 AM5/27/21
to fltkg...@googlegroups.com
On 5/27/21 5:07 PM Rob McDonald wrote:
I tested the following:

47ba6632b1be -- Tip of master
371eb6565494 -- Tip of branch-1.3

Both worked great!

Thanks for testing again. This is very much appreciated.


Thanks Manolo, Albrecht, & Greg.

Welcome
Reply all
Reply to author
Forward
0 new messages