大佬教程收集整理的这篇文章主要介绍了Xdnd drop 支持错误的实现 当前的 Dolphin 问题上一期 Thunar 问题,大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。
我前段时间在 VTK 中实现了 Xdnd drop 支持实现。除了 Thunar 文件管理器外,它工作得很好。当时所有其他文件管理器都运行良好。我们当时认为这个限制是一个 Thunar 错误。
我实现的功能非常简单:
没什么特别的,我什至没有触及列表类型。
快进几年,现在 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
从一些测试来看,问题在于处理 XdndFinished
事件时 Clientmessage
SELEctionNotify
的准备和发送回拖放源。
代替:
reply.xclient.window = event->xclient.data.l[0];
该行应该是:
reply.xclient.window = this->Xdndsource;
这会将 XClientmessageEvent
window
成员与目标窗口参数对齐为 XSendEvent
。这可能是一个简单的复制粘贴错误,因为 xclient
对 SELEctionNotify
事件类型无效。很可能之前未检查 window
的实际值,但最近已更改,因此出现错误。
spec 很好地涵盖了这一点,还提出了一些其他需要考虑的事项:
data.l[1]
:“如果当前目标接受放置并成功执行接受的放置操作,则设置位 0。(版本 5 中的新增功能)”,因此在技术上使用 itemCount
作为值计数为偶数时不正确XdndPosition
的处理不需要实际跟踪当前位置的位置(即,如果您只是将整个窗口用作放置目标),则您可以避免发送XdndStatus
响应 XdndEnter
消息进一步研究这个问题,我对 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
而 Thunar 仅支持以下内容:
以上是大佬教程为你收集整理的Xdnd drop 支持错误的实现 当前的 Dolphin 问题上一期 Thunar 问题全部内容,希望文章能够帮你解决Xdnd drop 支持错误的实现 当前的 Dolphin 问题上一期 Thunar 问题所遇到的程序开发问题。
如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。
本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。