RGFW 세부 정보: XDrag n Drop
소개
X11로 Drag 'n Drop 이벤트를 처리하려면 XDnD 프로토콜을 사용해야 합니다. XDnD 프로토콜은 다른 Drag 'n Drop API보다 훨씬 더 복잡하지만 이론상으로는 여전히 상대적으로 간단합니다. 하지만 이를 구현하려면 X11 서버 및 소스창과의 원활한 통신이 필요하기 때문에 지루한 작업입니다.
이 튜토리얼에서는 XDnD 프로토콜을 처리하고 X11 Drag 'n Drop 이벤트를 관리하는 방법을 설명합니다. 해당 코드는 RGFW의 소스코드를 기반으로 작성되었습니다.
개요
필요한 단계에 대한 자세한 개요:
먼저 X11 Atom이 초기화됩니다. X11 Atom은 X11을 통해 특정 데이터나 속성을 요청하거나 보내는 데 사용됩니다.
그런 다음 창의 속성이 변경되어 XDND(X Drag 'n Drop) 이벤트를 인식할 수 있습니다.
드래그가 발생하면 창은 드래그가 시작되었음을 대상 창에 알리는 XdndEnter 메시지가 포함된 ClientMessage 이벤트를 수신합니다.
드래그가 진행되는 동안 소스 창은 ClientMessage 이벤트를 통해 드래그에 대한 업데이트를 대상 창으로 보냅니다. 대상 창이 업데이트를 받을 때마다 업데이트를 받았는지 확인해야 합니다. 그렇지 않으면 상호작용이 종료됩니다.
드롭이 발생하면 소스 창은 XdndDrop 메시지를 보냅니다. 그런 다음 대상 창은 X11을 통해 드롭 선택을 변환하고 SelectionNotify 이벤트를 수신하여 변환된 데이터를 가져옵니다.
대상 창은 이 이벤트를 처리하고 데이터를 읽을 수 있는 문자열로 변환한 다음 마지막으로 XdndFinished 원자와 함께 ClientMessage를 보내 상호 작용이 완료되었음을 소스 창에 알립니다.
필요한 단계에 대한 간략한 개요:
1) X11 Atom 정의
2) 창에 XDnD 이벤트 활성화
3) ClientMessage를 통해 XDnD 이벤트 처리
4) ClientMessage를 통해 XDnD 드롭 데이터를 가져오고 상호작용을 종료합니다
1단계(X11 원자 정의)
XDnD 이벤트를 처리하려면 XInternAtom을 통해 XDnD Atom을 초기화해야 합니다. Atom은 특정 데이터나 작업을 보내거나 요청할 때 사용됩니다.
XdndTypeList는 대상 창이 소스 창에서 지원하는 데이터 유형을 알고 싶을 때 사용됩니다.
XdndSelection은 삭제 후 데이터 선택을 검사하고 변환 후 데이터를 검색하는 데 사용됩니다.
const Atom XdndTypeList = XInternAtom(display, "XdndTypeList", False); const Atom XdndSelection = XInternAtom(display, "XdndSelection", False);
이러한 일반 Xdnd 원자는 XdndStatus를 제외하고 소스 창에서 보낸 메시지입니다.
XdndEnter는 드롭이 대상 창에 들어갔을 때 사용됩니다.
XdndPosition은 드롭 위치에서 대상 창을 업데이트하는 데 사용됩니다.
XdndStatus는 대상이 메시지를 수신했음을 소스 창에 알리는 데 사용됩니다.
XdndLeave는 드롭이 대상 창을 떠났을 때 사용됩니다.
XdndDrop은 드롭이 대상 창에 떨어졌을 때 사용됩니다.
XdndFinished는 드롭이 완료되었을 때 사용됩니다.
const Atom XdndEnter = XInternAtom(display, "XdndEnter", False); const Atom XdndPosition = XInternAtom(display, "XdndPosition", False); const Atom XdndStatus = XInternAtom(display, "XdndStatus", False); const Atom XdndLeave = XInternAtom(display, "XdndLeave", False); const Atom XdndDrop = XInternAtom(display, "XdndDrop", False); const Atom XdndFinished = XInternAtom(display, "XdndFinished", False);
Xdnd Actions는 대상 창이 드래그 데이터로 수행하려는 작업입니다.
XdndActionCopy는 대상 창이 드래그 데이터를 복사하려고 할 때 사용됩니다.
const Atom XdndActionCopy = XInternAtom(display, "XdndActionCopy", False);
드롭 데이터의 형식을 확인하려면 text/uri-list 및 text/plain Atom이 필요합니다.
const Atom XtextUriList = XInternAtom((Display*) display, "text/uri-list", False); const Atom XtextPlain = XInternAtom((Display*) display, "text/plain", False);
2단계(창에 XDnD 이벤트 활성화)
XDnD 이벤트를 수신하려면 창에서 XDndAware Atom을 활성화해야 합니다. 이 원자는 창 관리자와 소스 창에 창이 XDnD 이벤트를 수신하려고 함을 알려줍니다.
이 작업은 XdndAware 원자를 생성하고 XChangeProperty를 사용하여 창의 XdndAware 속성을 변경하여 수행할 수 있습니다.
또한 포인터를 사용하여 XDnD 버전을 설정해야 하며, 버전 5는 XDnD 프로토콜의 최신 버전이므로 사용해야 합니다.
const Atom XdndAware = XInternAtom(display, "XdndAware", False); const char myversion = 5; XChangeProperty(display, window, XdndAware, 4, 32, PropModeReplace, &myversion, 1);
3단계(ClientMessage를 통해 XDnD 이벤트 처리)
이벤트를 처리하기 전에 일부 변수를 정의해야 합니다.
이러한 변수는 소스 창을 통해 제공되며 여러 인스턴스에서 사용됩니다.
이러한 변수는 소스 창, 사용된 XDnD Protocall 버전, 드롭 데이터 형식입니다.
int64_t source, version; int32_t format;
이제 ClientMessage 이벤트를 처리할 수 있습니다.
case ClientMessage:
먼저 XDnD 이벤트에 응답하기 위한 일반 XEvent 구조를 만듭니다. 이는 선택 사항이지만 이를 사용하면 작업량이 줄어듭니다.
이렇게 하면 이벤트가 소스 창으로 전송되고 데이터에 우리 창(대상)이 포함됩니다.
XEvent reply = { ClientMessage }; reply.xclient.window = source; reply.xclient.format = 32; reply.xclient.data.l[0] = (long) window; reply.xclient.data.l[1] = 0; reply.xclient.data.l[2] = None;
ClientMessage 이벤트 구조는 XEvent.xclient를 통해 액세스할 수 있습니다.
message_type은 구조의 속성으로, 메시지 유형이 무엇인지 보유합니다. 메시지 유형이 XDnD 메시지인지 확인하는 데 사용하겠습니다.
우리가 처리할 XDnD 이벤트는 XdndEnter, XdndPosition, XdndDrop 3가지입니다.
3.1단계(XdndEnter)
XdndEnter는 드롭이 대상 창에 들어갈 때 전송됩니다.
if (E.xclient.message_type == XdndEnter) {
먼저 RGFW는 필수 변수를 초기화합니다.
- count: number of formats in the the format list,
- formats: the list of supported formats and
- real_formats: this is used here to avoid running malloc for each drop
unsigned long count; Atom* formats; Atom real_formats[6];
We can also create a bool to check if the supported formats are a list or if there is only one format.
This can be done by using the xclient's data attribute. Data is a list of data about the event.
the first item is the source window.
The second item of the data includes two values, if the format is a list or not and the version of XDnD used.
To get the bool value, you can check the first bit, the version is stored 24 bits after (the final 40 bits).
The format should be set to None for now, also make sure the version is less than or equal to 5. Otherwise, there's probably an issue because 5 is the newest version.
Bool list = E.xclient.data.l[1] & 1; source = E.xclient.data.l[0]; version = E.xclient.data.l[1] >> 24; format = None; if (version > 5) break;
If the format is a list, we'll have to get the format list from the source window's XDndTypeList value using XGetWindowProperty
if (list) { Atom actualType; int32_t actualFormat; unsigned long bytesAfter; XGetWindowProperty((Display*) display, source, XdndTypeList, 0, LONG_MAX, False, 4, &actualType, &actualFormat, &count, &bytesAfter, (unsigned char**) &formats); }
Otherwise, the format can be found using the leftover xclient values (2 - 4)
else { count = 0; if (E.xclient.data.l[2] != None) real_formats[count++] = E.xclient.data.l[2]; if (E.xclient.data.l[3] != None) real_formats[count++] = E.xclient.data.l[3]; if (E.xclient.data.l[4] != None) real_formats[count++] = E.xclient.data.l[4]; formats = real_formats; }
Now that we have the format array, we can check if the format matches any of the formats we're looking for.
The list should also be freed using XFree if it was received using XGetWindowProperty.
unsigned long i; for (i = 0; i < count; i++) { if (formats[i] == XtextUriList || formats[i] == XtextPlain) { format = formats[i]; break; } } if (list) { XFree(formats); } break; }
Step 3.2 (XdndPosition)
XdndPosition is used when the drop position is updated.
Before we handle the event, make sure the version is correct.
if (E.xclient.message_type == XdndPosition && version <= 5)) {
The absolute X and Y can be found using the second item of the data list.
The X = the last 32 bits.
The Y = the first 32 bits.
const int32_t xabs = (E.xclient.data.l[2] >> 16) & 0xffff; const int32_t yabs = (E.xclient.data.l[2]) & 0xffff;
The absolute X and Y can be translated to the actual X and Y coordinates of the drop position using XTranslateCoordinates.
Window dummy; int32_t xpos, ypos; XTranslateCoordinates((Display*) display, XDefaultRootWindow((Display*) display), (Window) window, xabs, yabs, &xpos, &ypos, &dummy); printf("File drop starting at %i %i\n", xpos, ypos);
A response must be sent back to the source window. The response uses XdndStatus to tell the window it has received the message.
We should also tell the source the action accepted with the data. (XdndActionCopy)
The message can be sent out via XSendEvent make sure you also send out XFlush to make sure the event is pushed out.
reply.xclient.message_type = XdndStatus; if (format) { reply.xclient.data.l[1] = 1; if (version >= 2) reply.xclient.data.l[4] = XdndActionCopy; } XSendEvent((Display*) display, source, False, NoEventMask, &reply); XFlush((Display*) display); break; }
Step 3.3 (XdndDrop)
Before we handle the event, make sure the version is correct.
XdndDrop occurs when the item has been dropped.
if (E.xclient.message_type = XdndDrop && version <= 5) {
First, we should make sure we registered a valid format earlier.
if (format) {
We can use XConvertSection to request that the selection be converted to the format.
We will get the result in an SelectionNotify event.
// newer versions of xDnD require us to tell the source our time Time time = CurrentTime; if (version >= 1) time = E.xclient.data.l[2]; XConvertSelection((Display*) display, XdndSelection, format, XdndSelection, (Window) window, time); }
Otherwise, there is no drop data and the drop has ended. XDnD versions 2 and older require the target to tell the source when the drop has ended.
This can be done by sending out a ClientMessage event with the XdndFinished message type.
else if (version >= 2) { reply.xclient.message_type = XdndFinished; XSendEvent((Display*) display, source, False, NoEventMask, &reply); XFlush((Display*) display); } }
Step 4 (Get the XDnD drop data via ClientMessage and end the interaction)
Now we can receive the converted selection from the SlectionNotify event
case SelectionNotify: {
To do this, first, ensure the property is the XdndSelection.
/* this is only for checking for drops */ if (E.xselection.property != XdndSelection) break;
XGetWindowpropery can be used to get the selection data.
char* data; unsigned long result; Atom actualType; int32_t actualFormat; unsigned long bytesAfter; XGetWindowProperty((Display*) display, E.xselection.requestor, E.xselection.property, \ 0, LONG_MAX, False, E.xselection.target, &actualType, &actualFormat, &result, &bytesAfter, (unsigned char**) &data); if (result == 0) break; printf("File dropped: %s\n", data);
This is the raw string data for the drop. If there are multiple drops, it will include the files separated by a '\n'. If you'd prefer an array of strings, you'd have to parse the data into an array.
The data should also be freed once you're done using it.
If you want to use the data after the event has been processed, you should allocate a separate buffer and copy the data over.
if (data) XFree(data);
the drop has ended and XDnD versions 2 and older require the target to tell the source when the drop has ended.
This can be done by sending out a ClientMessage event with the XdndFinished message type.
It will also include the action we did with the data and the result to tell the source wether or not we actually got the data.
if (version >= 2) { reply.xclient.message_type = XdndFinished; reply.xclient.data.l[1] = result; reply.xclient.data.l[2] = XdndActionCopy; XSendEvent((Display*) display, source, False, NoEventMask, &reply); XFlush((Display*) display); }
Full code example
// This compiles with // gcc example.c -lX11 #include#include #include #include int main(void) { Display* display = XOpenDisplay(NULL); Window window = XCreateSimpleWindow(display, RootWindow(display, DefaultScreen(display)), 10, 10, 200, 200, 1, BlackPixel(display, DefaultScreen(display)), WhitePixel(display, DefaultScreen(display))); XSelectInput(display, window, ExposureMask | KeyPressMask); const Atom wm_delete_window = XInternAtom((Display*) display, "WM_DELETE_WINDOW", False); /* Xdnd code */ /* fetching data */ const Atom XdndTypeList = XInternAtom(display, "XdndTypeList", False); const Atom XdndSelection = XInternAtom(display, "XdndSelection", False); /* client messages */ const Atom XdndEnter = XInternAtom(display, "XdndEnter", False); const Atom XdndPosition = XInternAtom(display, "XdndPosition", False); const Atom XdndStatus = XInternAtom(display, "XdndStatus", False); const Atom XdndLeave = XInternAtom(display, "XdndLeave", False); const Atom XdndDrop = XInternAtom(display, "XdndDrop", False); const Atom XdndFinished = XInternAtom(display, "XdndFinished", False); /* actions */ const Atom XdndActionCopy = XInternAtom(display, "XdndActionCopy", False); const Atom XdndActionMove = XInternAtom(display, "XdndActionMove", False); const Atom XdndActionLink = XInternAtom(display, "XdndActionLink", False); const Atom XdndActionAsk = XInternAtom(display, "XdndActionAsk", False); const Atom XdndActionPrivate = XInternAtom(display, "XdndActionPrivate", False); const Atom XtextUriList = XInternAtom((Display*) display, "text/uri-list", False); const Atom XtextPlain = XInternAtom((Display*) display, "text/plain", False); const Atom XdndAware = XInternAtom(display, "XdndAware", False); const char myVersion = 5; XChangeProperty(display, window, XdndAware, 4, 32, PropModeReplace, &myVersion, 1); XMapWindow(display, window); XEvent E; Bool running = True; int64_t source, version; int32_t format; while (running) { XNextEvent(display, &E); switch (E.type) { case KeyPress: running = False; break; case ClientMessage: if (E.xclient.data.l[0] == (int64_t) wm_delete_window) { running = False; break; } XEvent reply = { ClientMessage }; reply.xclient.window = source; reply.xclient.format = 32; reply.xclient.data.l[0] = (long) window; reply.xclient.data.l[2] = 0; reply.xclient.data.l[3] = 0; if (E.xclient.message_type == XdndEnter) { unsigned long count; Atom* formats; Atom real_formats[6]; Bool list = E.xclient.data.l[1] & 1; source = E.xclient.data.l[0]; version = E.xclient.data.l[1] >> 24; format = None; if (version > 5) break; if (list) { Atom actualType; int32_t actualFormat; unsigned long bytesAfter; XGetWindowProperty((Display*) display, source, XdndTypeList, 0, LONG_MAX, False, 4, &actualType, &actualFormat, &count, &bytesAfter, (unsigned char**) &formats); } else { count = 0; if (E.xclient.data.l[2] != None) real_formats[count++] = E.xclient.data.l[2]; if (E.xclient.data.l[3] != None) real_formats[count++] = E.xclient.data.l[3]; if (E.xclient.data.l[4] != None) real_formats[count++] = E.xclient.data.l[4]; formats = real_formats; } unsigned long i; for (i = 0; i < count; i++) { if (formats[i] == XtextUriList || formats[i] == XtextPlain) { format = formats[i]; break; } } if (list) { XFree(formats); } break; } if (E.xclient.message_type == XdndPosition) { const int32_t xabs = (E.xclient.data.l[2] >> 16) & 0xffff; const int32_t yabs = (E.xclient.data.l[2]) & 0xffff; Window dummy; int32_t xpos, ypos; if (version > 5) break; XTranslateCoordinates((Display*) display, XDefaultRootWindow((Display*) display), (Window) window, xabs, yabs, &xpos, &ypos, &dummy); printf("File drop starting at %i %i\n", xpos, ypos); reply.xclient.message_type = XdndStatus; if (format) { reply.xclient.data.l[1] = 1; if (version >= 2) reply.xclient.data.l[4] = XdndActionCopy; } XSendEvent((Display*) display, source, False, NoEventMask, &reply); XFlush((Display*) display); break; } if (E.xclient.message_type = XdndDrop && version <= 5) { if (format) { Time time = CurrentTime; if (version >= 1) time = E.xclient.data.l[2]; XConvertSelection((Display*) display, XdndSelection, format, XdndSelection, (Window) window, time); } else if (version >= 2) { reply.xclient.message_type = XdndFinished; XSendEvent((Display*) display, source, False, NoEventMask, &reply); XFlush((Display*) display); } } break; case SelectionNotify: { /* this is only for checking for drops */ if (E.xselection.property != XdndSelection) break; char* data; unsigned long result; Atom actualType; int32_t actualFormat; unsigned long bytesAfter; XGetWindowProperty((Display*) display, E.xselection.requestor, E.xselection.property, 0, LONG_MAX, False, E.xselection.target, &actualType, &actualFormat, &result, &bytesAfter, (unsigned char**) &data); if (result == 0) break; printf("File(s) dropped: %s\n", data); if (data) XFree(data); if (version >= 2) { reply.xclient.message_type = XdndFinished; reply.xclient.data.l[1] = result; reply.xclient.data.l[2] = XdndActionCopy; XSendEvent((Display*) display, source, False, NoEventMask, &reply); XFlush((Display*) display); } break; } default: break; } } XCloseDisplay(display); }
위 내용은 RGFW 세부 정보: XDrag n Drop의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

핫 AI 도구

Undresser.AI Undress
사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover
사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool
무료로 이미지를 벗다

Clothoff.io
AI 옷 제거제

Video Face Swap
완전히 무료인 AI 얼굴 교환 도구를 사용하여 모든 비디오의 얼굴을 쉽게 바꾸세요!

인기 기사

뜨거운 도구

메모장++7.3.1
사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전
중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기
강력한 PHP 통합 개발 환경

드림위버 CS6
시각적 웹 개발 도구

SublimeText3 Mac 버전
신 수준의 코드 편집 소프트웨어(SublimeText3)

C#과 C의 역사와 진화는 독특하며 미래의 전망도 다릅니다. 1.C는 1983 년 Bjarnestroustrup에 의해 발명되어 객체 지향 프로그래밍을 C 언어에 소개했습니다. Evolution 프로세스에는 자동 키워드 소개 및 Lambda Expressions 소개 C 11, C 20 도입 개념 및 코 루틴과 같은 여러 표준화가 포함되며 향후 성능 및 시스템 수준 프로그래밍에 중점을 둘 것입니다. 2.C#은 2000 년 Microsoft에 의해 출시되었으며 C와 Java의 장점을 결합하여 진화는 단순성과 생산성에 중점을 둡니다. 예를 들어, C#2.0은 제네릭과 C#5.0 도입 된 비동기 프로그래밍을 소개했으며, 이는 향후 개발자의 생산성 및 클라우드 컴퓨팅에 중점을 둘 것입니다.

C# 및 C 및 개발자 경험의 학습 곡선에는 상당한 차이가 있습니다. 1) C#의 학습 곡선은 비교적 평평하며 빠른 개발 및 기업 수준의 응용 프로그램에 적합합니다. 2) C의 학습 곡선은 가파르고 고성능 및 저수준 제어 시나리오에 적합합니다.

C에서 정적 분석의 적용에는 주로 메모리 관리 문제 발견, 코드 로직 오류 확인 및 코드 보안 개선이 포함됩니다. 1) 정적 분석은 메모리 누출, 이중 릴리스 및 초기화되지 않은 포인터와 같은 문제를 식별 할 수 있습니다. 2) 사용하지 않은 변수, 데드 코드 및 논리적 모순을 감지 할 수 있습니다. 3) Coverity와 같은 정적 분석 도구는 버퍼 오버플로, 정수 오버플로 및 안전하지 않은 API 호출을 감지하여 코드 보안을 개선 할 수 있습니다.

C는 XML과 타사 라이브러리 (예 : TinyXML, Pugixml, Xerces-C)와 상호 작용합니다. 1) 라이브러리를 사용하여 XML 파일을 구문 분석하고 C- 처리 가능한 데이터 구조로 변환하십시오. 2) XML을 생성 할 때 C 데이터 구조를 XML 형식으로 변환하십시오. 3) 실제 애플리케이션에서 XML은 종종 구성 파일 및 데이터 교환에 사용되어 개발 효율성을 향상시킵니다.

C에서 Chrono 라이브러리를 사용하면 시간과 시간 간격을보다 정확하게 제어 할 수 있습니다. 이 도서관의 매력을 탐구합시다. C의 크로노 라이브러리는 표준 라이브러리의 일부로 시간과 시간 간격을 다루는 현대적인 방법을 제공합니다. 시간과 C 시간으로 고통받는 프로그래머에게는 Chrono가 의심 할 여지없이 혜택입니다. 코드의 가독성과 유지 가능성을 향상시킬뿐만 아니라 더 높은 정확도와 유연성을 제공합니다. 기본부터 시작합시다. Chrono 라이브러리에는 주로 다음 주요 구성 요소가 포함됩니다. std :: Chrono :: System_Clock : 현재 시간을 얻는 데 사용되는 시스템 클럭을 나타냅니다. STD :: 크론

C의 미래는 병렬 컴퓨팅, 보안, 모듈화 및 AI/기계 학습에 중점을 둘 것입니다. 1) 병렬 컴퓨팅은 코 루틴과 같은 기능을 통해 향상 될 것입니다. 2)보다 엄격한 유형 검사 및 메모리 관리 메커니즘을 통해 보안이 향상 될 것입니다. 3) 변조는 코드 구성 및 편집을 단순화합니다. 4) AI 및 머신 러닝은 C가 수치 컴퓨팅 및 GPU 프로그래밍 지원과 같은 새로운 요구에 적응하도록 촉구합니다.

c is nontdying; it'sevolving.1) c COMINGDUETOITSTIONTIVENICICICICINICE INPERFORMICALEPPLICATION.2) thelugageIscontinuousUllyUpdated, witcentfeatureslikemodulesandCoroutinestoimproveusActionalance.3) despitechallen

C의 DMA는 직접 메모리 액세스 기술인 DirectMemoryAccess를 말하며 하드웨어 장치는 CPU 개입없이 데이터를 메모리로 직접 전송할 수 있습니다. 1) DMA 운영은 하드웨어 장치 및 드라이버에 크게 의존하며 구현 방법은 시스템마다 다릅니다. 2) 메모리에 직접 액세스하면 보안 위험이 발생할 수 있으며 코드의 정확성과 보안이 보장되어야합니다. 3) DMA는 성능을 향상시킬 수 있지만 부적절하게 사용하면 시스템 성능이 저하 될 수 있습니다. 실습과 학습을 통해 우리는 DMA 사용 기술을 습득하고 고속 데이터 전송 및 실시간 신호 처리와 같은 시나리오에서 효과를 극대화 할 수 있습니다.
