程序问答   发布时间:2022-06-02  发布网站:大佬教程  code.js-code.com
大佬教程收集整理的这篇文章主要介绍了Xdnd drop 支持错误的实现 当前的 Dolphin 问题上一期 Thunar 问题大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。

如何解决Xdnd drop 支持错误的实现 当前的 Dolphin 问题上一期 Thunar 问题?

开发过程中遇到Xdnd drop 支持错误的实现 当前的 Dolphin 问题上一期 Thunar 问题的问题如何解决?下面主要结合日常开发的经验,给出你关于Xdnd drop 支持错误的实现 当前的 Dolphin 问题上一期 Thunar 问题的解决方法建议,希望对你解决Xdnd drop 支持错误的实现 当前的 Dolphin 问题上一期 Thunar 问题有所启发或帮助;

我前段时间在 VTK 中实现了 Xdnd drop 支持实现。除了 Thunar 文件管理器外,它工作得很好。当时所有其他文件管理器都运行良好。我们当时认为这个限制是一个 Thunar 错误。

我实现的功能非常简单:

  • 将应用程序的窗口设置为 XdndAware
  • 接收位置信息并回复我们已准备好接收
  • 接收丢弃消息并请求选择
  • 接收选择通知并恢复URI
  • 将 URI 转换为我们可以使用的内容
  • @H_618_17@

    没什么特别的,我什至没有触及列表类型。

    快进几年,现在 dolphin 用户无法将文件正确放入@R_753_9616@程序中。自 dolphin 启动以来,URI 始终是第一个删除的文件。重新启动@R_753_9616@程序没有任何效果。 pcmanfm 完全没有错误。

    这不是 dolphin 的错误,文件可以从 dolphin 放到 Blender 或 firefox 上而不会出现问题。

    所以我们的实现中肯定有一个错误,但我已经盯着代码看了一段时间,我尝试的一切都没有效果,除了完全破坏 Xdnd 支持。

    这是实现中有趣的部分:

    //------------------------------------------------------------------------------
    vtkXRenderWindowInteractor::vtkXRenderWindowInteractor()
    {
      this->Internal = new vtkXRenderWindowInteractorInternals;
      this->displayID = nullptr;
      this->WindowID = 0;
      this->KillAtom = 0;
      this->Xdndsource = 0;
      this->XdndpositionAtom = 0;
      this->XdndDropAtom = 0;
      this->XdndActioncopyAtom = 0;
      this->XdndStatusAtom = 0;
      this->XdndFinishedAtom = 0;
    }
    
    [...]
    
    
    //------------------------------------------------------------------------------
    voID vtkXRenderWindowInteractor::Enable()
    {
      // avoID cycles of calling Initialize() and Enable()
      if (this->Enabled)
      {
        return;
      }
    
      // Add the event handler to the system.
      // If we change the types of events processed by this handler,then
      // we need to change the disable() routIne to match.  In order for disable()
      // to work properly,both the callBACk function and the clIEnt data
      // passed to XtAddEventHandler and XtRemoveEventHandler must MATCH
      // PERFECTLY
      XSELEcTinput(this->displayID,this->WindowID,KeyPressmask | keyreleaseMask | buttonPressmask | buttonReleaseMask | ExposureMask |
          StructureNotifymask | EnterWindowMask | LeaveWindowMask | PointerMotionHintMask |
          PointerMotionMask);
    
      // Setup for capturing the window deletion
      this->KillAtom = XInternAtom(this->displayID,"WM_deletE_WINDOW",falsE);
      XSetWMProtocols(this->displayID,&this->KillAtom,1);
    
      // Enable drag and drop
      Atom xdndAwareAtom = XInternAtom(this->displayID,"XdndAware",falsE);
      char xdndVersion = 5;
      XChangeProperty(this->displayID,xdndAwareAtom,XA_ATOM,32,PropModereplace,(unsigned char*)&xdndVersion,1);
      this->XdndpositionAtom = XInternAtom(this->displayID,"Xdndposition",falsE);
      this->XdndDropAtom = XInternAtom(this->displayID,"XdndDrop",falsE);
      this->XdndActioncopyAtom = XInternAtom(this->displayID,"XdndActioncopy",falsE);
      this->XdndStatusAtom = XInternAtom(this->displayID,"XdndStatus",falsE);
      this->XdndFinishedAtom = XInternAtom(this->displayID,"XdndFinished",falsE);
    
      this->Enabled = 1;
    
      this->ModifIEd();
    }
    
    [...]
    
    //------------------------------------------------------------------------------
    voID vtkXRenderWindowInteractor::dispatchEvent(XEvent* event)
    {
      int xp,yp;
    
      switch (event->typE)
      {
    [...]
    
        // SELEction request for drag and drop has been delivered
        case SELEctionNotify:
        {
          // Sanity checks
          if (!event->xSELEction.property || !this->XdndsourcE)
          {
            return;
          }
    
          // Recover the dropped file
          char* data = nullptr;
          Atom actualType;
          int actualFormat;
          unsigned long itemCount,bytesAfter;
          XGetwindowProperty(this->displayID,event->xSELEction.requestor,event->xSELEction.property,LONG_MAX,false,event->xSELEction.target,&actualType,&actualFormat,&itemCount,&bytesAfter,(unsigned char**)&data);
    
          // Conversion checks
          if ((event->xSELEction.target != AnyPropertyType && actualType != event->xSELEction.target) ||
            itemCount == 0)
          {
            return;
          }
    
          // Recover filepaths from uris and invoke DropfilesEvent
          std::stringstream uris(data);
          std::string uri,protocol,hostname,filePath;
          std::string unused0,unused1,unused2,unused3;
          vtkNew<vtkStringArray> filePaths;
          while (std::getline(uris,uri,'\n'))
          {
            if (vtksys::SystemTools::ParseURL(
                  uri,unused0,unused3,filePath,truE))
            {
              if (protocol == "file" && (hostname.empty() || hostname == "localhost"))
              {
                // The uris can be crlf delimited,remove ending \r if any
                if (filePath.BACk() == '\r')
                {
                  filePath.pop_BACk();
                }
    
                // The extracted filepath miss the first slash
                filePath.insert(0,"/");
    
                filePaths->InsertNextValue(filePath);
              }
            }
          }
          this->InvokeEvent(vtkCommand::DropfilesEvent,filePaths);
          XFree(data);
    
          // Inform the source the the drag and drop operation was sucessfull
          XEvent reply;
          memset(&reply,sizeof(reply));
    
          reply.type = clIEntmessage;
          reply.xclIEnt.window = event->xclIEnt.data.l[0];
          reply.xclIEnt.message_type = this->XdndFinishedAtom;
          reply.xclIEnt.format = 32;
          reply.xclIEnt.data.l[0] = this->WindowID;
          reply.xclIEnt.data.l[1] = itemCount;
          reply.xclIEnt.data.l[2] = this->XdndActioncopyAtom;
    
          XSendEvent(this->displayID,this->Xdndsource,NoEventMask,&reply);
          XFlush(this->displayID);
          this->Xdndsource = 0;
        }
        break;
    
    
        case ClIEntmessage:
        {
          if (event->xclIEnt.message_type == this->XdndpositionAtom)
          {
            // Drag and drop event insIDe the window
    
            // Recover the position
            int xWindow,yWindow;
            int xRoot = event->xclIEnt.data.l[2] >> 16;
            int yRoot = event->xclIEnt.data.l[2] & 0xffff;
            Window root = DefaultRootwindow(this->displayID);
            Window child;
            XTranslateCoordinates(
              this->displayID,root,xRoot,yRoot,&xWindow,&yWindow,&child);
    
            // Convert it to VTK compatible LOCATIOn
            double LOCATIOn[2];
            LOCATIOn[0] = static_cast<double>(xWindow);
            LOCATIOn[1] = static_cast<double>(this->Size[1] - yWindow - 1);
            this->InvokeEvent(vtkCommand::updateDropLOCATIOnEvent,LOCATIOn);
    
            // Reply that we are ready to copy the dragged data
            XEvent reply;
            memset(&reply,sizeof(reply));
    
            reply.type = clIEntmessage;
            reply.xclIEnt.window = event->xclIEnt.data.l[0];
            reply.xclIEnt.message_type = this->XdndStatusAtom;
            reply.xclIEnt.format = 32;
            reply.xclIEnt.data.l[0] = this->WindowID;
            reply.xclIEnt.data.l[1] = 1; // Always accept the dnd with no rectangle
            reply.xclIEnt.data.l[2] = 0; // Specify an empty rectangle
            reply.xclIEnt.data.l[3] = 0;
            reply.xclIEnt.data.l[4] = this->XdndActioncopyAtom;
    
            XSendEvent(this->displayID,event->xclIEnt.data.l[0],&reply);
            XFlush(this->displayID);
          }
          else if (event->xclIEnt.message_type == this->XdndDropAtom)
          {
            // Item dropped in the window
            // Store the source of the drag and drop
            this->Xdndsource = event->xclIEnt.data.l[0];
    
            // Ask for a conversion of the SELEction. This will trigger a SELEctioNotify event later.
            Atom xdndSELEctionAtom = XInternAtom(this->displayID,"XdndSELEction",falsE);
            XConvertSELEction(this->displayID,xdndSELEctionAtom,XInternAtom(this->displayID,"UTF8_StriNG",falsE),CurrentTimE);
          }
          else if (static_cast<Atom>(event->xclIEnt.data.l[0]) == this->KillAtom)
          {
            this->ExitCallBACk();
          }
        }
        break;
      }
    }
    [...]
    

    和标题:

    #include "vtkRenderWindowInteractor.h"
    #include "vtkRenderingUIModule.h" // For export macro
    #include <X11/Xlib.h>             // Needed for X types in the public interface
    
    class vtkCallBACkCommand;
    class vtkXRenderWindowInteractorInternals;
    
    class VTKRENDERINGUI_EXPORT vtkXRenderWindowInteractor : public vtkRenderWindowInteractor
    {
    public:
      static vtkXRenderWindowInteractor* New();
      vtkTypeMacro(vtkXRenderWindowInteractor,vtkRenderWindowInteractor);
      voID PrintSelf(ostream& os,vtkIndent indent) overrIDe;
    
      /**
       * Initializes the event handlers without an XtAppContext.  This is
       * good for when you don't have a user interface,but you still
       * want to have mousE interaction.
       */
      voID Initialize() overrIDe;
    
      /**
       * Break the event loop on 'q','e' keypress. Want more ???
       */
      voID TerminateApp() overrIDe;
    
      /**
       * Run the event loop and return. This is provIDed so that you can
       * implement your own event loop but yet use the vtk event handling as
       * well.
       */
      voID ProcessEvents() overrIDe;
    
      ///@{
      /**
       * Enable/disablE interactions.  By default interactors are enabled when
       * initialized.  Initialize() must be called prior to enabling/disabling
       * interaction. these methods are used when a window/Widget is being
       * shared by multiple renderers and interactors.  This allows a "modal"
       * display where onE interactor is active when its data is to be displayed
       * and all other interactors associated with the Widget are Disabled
       * when their data is not displayed.
       */
      voID Enable() overrIDe;
      voID disable() overrIDe;
      ///@}
    
      /**
       * update the Size data member and set the associated RenderWindow's
       * size.
       */
      voID updateSize(int,int) overrIDe;
    
      /**
       * Re-defines virtual function to get mouse position by querying X-server.
       */
      voID GetMouseposition(int* x,int* y) overrIDe;
    
      voID dispatchEvent(XEvent*);
    
    protected:
      vtkXRenderWindowInteractor();
      ~vtkXRenderWindowInteractor() overrIDe;
    
      /**
       * update the Size data member and set the associated RenderWindow's
       * size but do not resize the XWindow.
       */
      voID updateSiZenoXResize(int,int);
    
      // Using static here to avoID destroying context when many apps are open:
      static int NumAppInitialized;
    
      display* displayID;
      Window WindowID;
      Atom KillAtom;
      int positionBeforeStereo[2];
      vtkXRenderWindowInteractorInternals* Internal;
    
      // Drag and drop related
      Window Xdndsource;
      Atom XdndpositionAtom;
      Atom XdndDropAtom;
      Atom XdndActioncopyAtom;
      Atom XdndStatusAtom;
      Atom XdndFinishedAtom;
    
      ///@{
      /**
       * X-specific internal timer methods. See the superclass for detailed
       * documentation.
       */
      int InternalCreateTimer(int timerID,int timerType,unsigned long duration) overrIDe;
      int InternalDestroyTimer(int platformTimerID) overrIDe;
      ///@}
    
      voID FireTimers();
    
      /**
       * This will start up the X event loop and never return. If you
       * call this method it will loop processing X events until the
       * application is exited.
       */
      voID StartEventLoop() overrIDe;
    
    private:
      vtkXRenderWindowInteractor(const vtkXRenderWindowInteractor&) = delete;
      voID operator=(const vtkXRenderWindowInteractor&) = delete;
    };
    
    #endif
    

    完整的文件可以在这里看到: https://gitlab.kitware.com/vtk/vtk/-/blob/master/Rendering/UI/vtkXRenderWindowInteractor.cxx

    你可以在这里按照我的思路和调试: @L_404_1@

    要测试此代码,一个简单的方法是使用 F3D 使用已删除的文件,但一个简单的 VTK 应用程序也应该可以工作: https://gitlab.kitware.com/f3d/f3d

    解决方法

    当前的 Dolphin 问题

    从一些测试来看,问题在于处理 XdndFinished 事件时 Clientmessage SELEctionNotify 的准备和发送回拖放源。

    代替:

    reply.xclient.window = event->xclient.data.l[0];
    

    该行应该是:

    reply.xclient.window = this->Xdndsource;
    

    这会将 XClientmessageEvent window 成员与目标窗口参数对齐为 XSendEvent。这可能是一个简单的复制粘贴错误,因为 xclientSELEctionNotify 事件类型无效。很可能之前未检查 window 的实际值,但最近已更改,因此出现错误。

    spec 很好地涵盖了这一点,还提出了一些其他需要虑的事项:

    • 对于 data.l[1]:“如果当前目标接受放置并成功执行接受的放置操作,则设置位 0。(版本 5 中的新增功能)”,因此在技术上使用 itemCount 作为值计数为偶数时不正确
    • 如果 XdndPosition 的处理不需要实际跟踪当前位置的位置(即,如果您只是将整个窗口用作放置目标),则您可以避免发送XdndStatus 响应 XdndEnter 消息
    • @H_618_17@

      上一期 Thunar 问题

      进一步研究这个问题,我对 Thunar 的前一个问题进行了一些故障排除,它归结为代码处理 XdndDrop,假设传入数据的格式可以转换为 UTF8_StriNG。 GLFW 的此 diff 处理几乎完全相同的问题。

      如果在处理 XdndEnter 消息时检查 xclient.data.l[2]xclient.data.l[4] 的值,您可以看到 Dolphin 报告支持以下格式:

      • text/uri-list
      • text/x-moz-url
      • text/plain
      • @H_618_17@

        而 Thunar 仅支持以下内容:

        • text/uri-list
        • @H_618_17@

          最简单的解决方案是:

          • 在处理 XdndEnter 时跟踪支持的格式
          • 在处理 XConvertSELEction(而不是 XdndDrop)时将此格式提供给 UTF8_StriNG
          • 在处理 SELEctionNotify 事件时适当处理格式
          • @H_618_17@

            更完整地说,如果在 xclient.data.l[1] 消息上设置了 XdndEnter 的第 0 位,您应该获取拖放源窗口的 XdndTypeList 属性并基于格式选择在此之上,而不是消息本身中包含的格式。

    大佬总结

    以上是大佬教程为你收集整理的Xdnd drop 支持错误的实现 当前的 Dolphin 问题上一期 Thunar 问题全部内容,希望文章能够帮你解决Xdnd drop 支持错误的实现 当前的 Dolphin 问题上一期 Thunar 问题所遇到的程序开发问题。

    如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。

    本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
    如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。