Moohasha
Moohasha

Reputation: 245

Qt transfer mouse move events to new window

I'm handling mouse events (through an event filter) on a QTabBar to detect when the user clicks and drags a tab to tear it off. When this happens, I remove the current widget from the QTabWidget and create a new top level widget that I add it to so that it's detached and floating, just like when you tear off a tab in Chrome. This new floating window is a custom frameless widget I made that has a custom titlebar that I handle mouse events on to allow the user to drag the window around the desktop.

The problem I'm having is that when you click and drag the tab to pull it off and the new top level window is created, I can't seem to get the application to continue dragging the new window without the user clicking and dragging on my titlebar. I'd like for the original drag motion to just transfer to the new widget so that the use can keep dragging it until he releases the mouse button.

I've tried creating a "fake" QMouseEvent to pass to my title bar (by calling QCoreApplication::sendEvent(object, event) to make it think it's been clicked on, but it doesn't receive any mouse move events unless you actually click on it. I'm open to other ideas.

Update: I added some debugging statements and it looks like once I detach the tab and create the new floating window, the QMainWindow continues to receive the mouse move events until I release the mouse button. I'll try adding some code to forward these mouse events on to the new floating window, but that feels kinda hacky.

Correction: The QMainWindow is not receiving the mouse move events, an object named "MainWindowWindow" is, which is a QWidgetWindow that I guess is a private type used to manage top level windows?

Upvotes: 0

Views: 745

Answers (1)

Moohasha
Moohasha

Reputation: 245

Ok, I got it working, but I don't like it. As I said in my correction, once the tab is detached, the QWidgetWindow starts receiving the mouse move events. This is a private type that's not exposed via the API.

What I ended up doing was installing an event filter on the application and looking for mouse events on an object that inherits from QWidgetWindow. I then directly call new drag() and endDrag() methods that I added to my floating window class. In my eventFilter method, it looks like this.

if (watched->inherits("QWidgetWindow"))
{
  if (floater) // <- the floating window that was recently detached
  {
    if (event->type() == QEvent::MouseMove)
    {
      floater->drag(QCursor::pos()); // <-- Pass global cursor pos
    }
    else if (event->type() == QEvent::MouseRelease)
    {
      floater->endDrag();
      floater = nullptr;
    }
  }
}

Like I said, if feels dirty because I A) am checking for events on a private type that I'm not really supposed to know about, and B) telling another window to drag around when it has code to do this itself. But it works, and I've spent enough time working on this. If someone has a more elegant solution, I'm happy to hear it.

Upvotes: 0

Related Questions