aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPo Lu2022-03-25 11:09:43 +0800
committerPo Lu2022-03-25 11:09:43 +0800
commitb4fc5bedb8fa3fbc48731da6fced2ba04efad449 (patch)
tree0f3be69b519e52ac8d223b048363e0d682e4a449
parent392d66f6f5d9962d0b0f96decbebd9db00cce1ab (diff)
downloademacs-b4fc5bedb8fa3fbc48731da6fced2ba04efad449.tar.gz
emacs-b4fc5bedb8fa3fbc48731da6fced2ba04efad449.zip
Use _NET_CLIENT_LIST_STACKING to optimize drag and drop window discovery
* src/xterm.c (struct x_client_list_window): New struct. (x_dnd_free_toplevels, x_dnd_compute_toplevels) (x_dnd_get_target_window_1): New functions. (x_dnd_get_target_window): Search in the toplevel list if it exists. (x_dnd_cleanup_drag_and_drop): Clean up toplevel list. (x_dnd_begin_drag_and_drop): Compute toplevel list if the window manager supports it. (handle_one_xevent): Update the toplevel list if prudent.
-rw-r--r--src/xterm.c316
1 files changed, 313 insertions, 3 deletions
diff --git a/src/xterm.c b/src/xterm.c
index 7a16704d6e0..0267ba7ec1b 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -820,12 +820,141 @@ static struct frame *x_dnd_frame;
820static XWindowAttributes x_dnd_old_window_attrs; 820static XWindowAttributes x_dnd_old_window_attrs;
821static bool x_dnd_unwind_flag; 821static bool x_dnd_unwind_flag;
822 822
823struct x_client_list_window
824{
825 Window window;
826 Display *dpy;
827 int x, y;
828 int width, height;
829 bool visible_p;
830 long previous_event_mask;
831
832 struct x_client_list_window *next;
833};
834
835static struct x_client_list_window *x_dnd_toplevels = NULL;
836static bool x_dnd_use_toplevels;
837
838static void
839x_dnd_free_toplevels (void)
840{
841 struct x_client_list_window *last;
842 struct x_client_list_window *tem = x_dnd_toplevels;
843
844 while (tem)
845 {
846 last = tem;
847 tem = tem->next;
848
849 x_catch_errors (last->dpy);
850 XSelectInput (last->dpy, last->window,
851 last->previous_event_mask);
852 x_uncatch_errors ();
853 xfree (last);
854 }
855
856 x_dnd_toplevels = NULL;
857}
858
859static int
860x_dnd_compute_toplevels (struct x_display_info *dpyinfo)
861{
862 Atom type;
863 Window *toplevels, child;
864 int format, rc, dest_x, dest_y;
865 unsigned long nitems, bytes_after;
866 unsigned char *data = NULL;
867 unsigned long i;
868 XWindowAttributes attrs;
869 struct x_client_list_window *tem;
870
871 rc = XGetWindowProperty (dpyinfo->display, dpyinfo->root_window,
872 dpyinfo->Xatom_net_client_list_stacking,
873 0, LONG_MAX, False, XA_WINDOW, &type,
874 &format, &nitems, &bytes_after, &data);
875
876 if (rc != Success)
877 return 1;
878
879 if (format != 32 || type != XA_WINDOW)
880 {
881 XFree (data);
882 return 1;
883 }
884
885 toplevels = (Window *) data;
886
887 /* Actually right because _NET_CLIENT_LIST_STACKING has bottom-up
888 order. */
889 for (i = 0; i < nitems; ++i)
890 {
891 x_catch_errors (dpyinfo->display);
892 rc = (XGetWindowAttributes (dpyinfo->display,
893 toplevels[i], &attrs)
894 && !x_had_errors_p (dpyinfo->display));
895
896 if (rc)
897 rc = (XTranslateCoordinates (dpyinfo->display, toplevels[i],
898 attrs.root, -attrs.border_width,
899 -attrs.border_width, &dest_x,
900 &dest_y, &child)
901 && !x_had_errors_p (dpyinfo->display));
902 x_uncatch_errors_after_check ();
903
904 if (rc)
905 {
906 tem = xmalloc (sizeof *tem);
907 tem->window = toplevels[i];
908 tem->dpy = dpyinfo->display;
909 tem->x = dest_x;
910 tem->y = dest_y;
911 tem->width = attrs.width + attrs.border_width;
912 tem->height = attrs.height + attrs.border_width;
913 tem->visible_p = (attrs.map_state == IsViewable);
914 tem->next = x_dnd_toplevels;
915 tem->previous_event_mask = attrs.your_event_mask;
916
917 x_catch_errors (dpyinfo->display);
918 XSelectInput (dpyinfo->display, toplevels[i],
919 attrs.your_event_mask | StructureNotifyMask);
920 x_uncatch_errors ();
921
922 x_dnd_toplevels = tem;
923 }
924 }
925
926 return 0;
927}
928
823#define X_DND_SUPPORTED_VERSION 5 929#define X_DND_SUPPORTED_VERSION 5
824 930
825static int x_dnd_get_window_proto (struct x_display_info *, Window); 931static int x_dnd_get_window_proto (struct x_display_info *, Window);
826static Window x_dnd_get_window_proxy (struct x_display_info *, Window); 932static Window x_dnd_get_window_proxy (struct x_display_info *, Window);
827 933
828static Window 934static Window
935x_dnd_get_target_window_1 (struct x_display_info *dpyinfo,
936 int root_x, int root_y)
937{
938 struct x_client_list_window *tem;
939
940 /* Loop through x_dnd_toplevels until we find the toplevel where
941 root_x and root_y are. */
942
943 for (tem = x_dnd_toplevels; tem; tem = tem->next)
944 {
945 if (!tem->visible_p)
946 continue;
947
948 if (root_x >= tem->x && root_y >= tem->y
949 && root_x < tem->x + tem->width
950 && root_y < tem->y + tem->height)
951 return tem->window;
952 }
953
954 return None;
955}
956
957static Window
829x_dnd_get_target_window (struct x_display_info *dpyinfo, 958x_dnd_get_target_window (struct x_display_info *dpyinfo,
830 int root_x, int root_y, int *proto_out) 959 int root_x, int root_y, int *proto_out)
831{ 960{
@@ -841,6 +970,76 @@ x_dnd_get_target_window (struct x_display_info *dpyinfo,
841 970
842 proto = -1; 971 proto = -1;
843 972
973 if (x_dnd_use_toplevels)
974 {
975 child = x_dnd_get_target_window_1 (dpyinfo, root_x, root_y);
976
977 if (child != None)
978 {
979 proxy = x_dnd_get_window_proxy (dpyinfo, child_return);
980
981 if (proxy != None)
982 {
983 proto = x_dnd_get_window_proto (dpyinfo, proxy);
984
985 if (proto != -1)
986 {
987 *proto_out = proto;
988 return proxy;
989 }
990 }
991
992 *proto_out = x_dnd_get_window_proto (dpyinfo, child);
993 return child;
994 }
995
996 /* Then look at the composite overlay window. */
997#if defined HAVE_XCOMPOSITE && (XCOMPOSITE_MAJOR > 0 || XCOMPOSITE_MINOR > 2)
998 if (dpyinfo->composite_supported_p
999 && (dpyinfo->composite_major > 0
1000 || dpyinfo->composite_minor > 2))
1001 {
1002 if (XGetSelectionOwner (dpyinfo->display,
1003 dpyinfo->Xatom_NET_WM_CM_Sn) != None)
1004 {
1005 x_catch_errors (dpyinfo->display);
1006 overlay_window = XCompositeGetOverlayWindow (dpyinfo->display,
1007 dpyinfo->root_window);
1008 XCompositeReleaseOverlayWindow (dpyinfo->display,
1009 dpyinfo->root_window);
1010 if (!x_had_errors_p (dpyinfo->display))
1011 {
1012 XGetWindowAttributes (dpyinfo->display, overlay_window, &attrs);
1013
1014 if (attrs.map_state == IsViewable)
1015 {
1016 proxy = x_dnd_get_window_proxy (dpyinfo, overlay_window);
1017
1018 if (proxy != None)
1019 {
1020 proto = x_dnd_get_window_proto (dpyinfo, proxy);
1021
1022 if (proto != -1)
1023 {
1024 *proto_out = proto;
1025 x_uncatch_errors_after_check ();
1026
1027 return proxy;
1028 }
1029 }
1030 }
1031 }
1032 x_uncatch_errors_after_check ();
1033 }
1034 }
1035#endif
1036
1037 /* No toplevel was found and the overlay window was not a proxy,
1038 so return None. */
1039 *proto_out = -1;
1040 return None;
1041 }
1042
844 /* Not strictly necessary, but satisfies GCC. */ 1043 /* Not strictly necessary, but satisfies GCC. */
845 child = dpyinfo->root_window; 1044 child = dpyinfo->root_window;
846 1045
@@ -1005,7 +1204,7 @@ x_dnd_get_window_proto (struct x_display_info *dpyinfo, Window wdesc)
1005 unsigned long n, left; 1204 unsigned long n, left;
1006 bool had_errors; 1205 bool had_errors;
1007 1206
1008 if (wdesc == None || wdesc == FRAME_X_WINDOW (x_dnd_frame)) 1207 if (wdesc == None || wdesc == FRAME_OUTER_WINDOW (x_dnd_frame))
1009 return -1; 1208 return -1;
1010 1209
1011 x_catch_errors (dpyinfo->display); 1210 x_catch_errors (dpyinfo->display);
@@ -1182,6 +1381,9 @@ x_dnd_cleanup_drag_and_drop (void *frame)
1182 1381
1183 x_dnd_waiting_for_finish = false; 1382 x_dnd_waiting_for_finish = false;
1184 1383
1384 if (x_dnd_use_toplevels)
1385 x_dnd_free_toplevels ();
1386
1185 FRAME_DISPLAY_INFO (f)->grabbed = 0; 1387 FRAME_DISPLAY_INFO (f)->grabbed = 0;
1186#ifdef USE_GTK 1388#ifdef USE_GTK
1187 current_hold_quit = NULL; 1389 current_hold_quit = NULL;
@@ -7036,6 +7238,18 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction,
7036 x_dnd_return_frame = 0; 7238 x_dnd_return_frame = 0;
7037 x_dnd_waiting_for_finish = false; 7239 x_dnd_waiting_for_finish = false;
7038 x_dnd_end_window = None; 7240 x_dnd_end_window = None;
7241 x_dnd_use_toplevels
7242 = x_wm_supports (f, FRAME_DISPLAY_INFO (f)->Xatom_net_client_list_stacking);
7243 x_dnd_toplevels = NULL;
7244
7245 if (x_dnd_use_toplevels)
7246 {
7247 if (x_dnd_compute_toplevels (FRAME_DISPLAY_INFO (f)))
7248 {
7249 x_dnd_free_toplevels ();
7250 x_dnd_use_toplevels = false;
7251 }
7252 }
7039 7253
7040 if (return_frame_p) 7254 if (return_frame_p)
7041 x_dnd_return_frame = 1; 7255 x_dnd_return_frame = 1;
@@ -7128,6 +7342,9 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction,
7128 x_dnd_waiting_for_finish = false; 7342 x_dnd_waiting_for_finish = false;
7129 } 7343 }
7130 7344
7345 if (x_dnd_use_toplevels)
7346 x_dnd_free_toplevels ();
7347
7131 FRAME_DISPLAY_INFO (f)->grabbed = 0; 7348 FRAME_DISPLAY_INFO (f)->grabbed = 0;
7132#ifdef USE_GTK 7349#ifdef USE_GTK
7133 current_hold_quit = NULL; 7350 current_hold_quit = NULL;
@@ -7162,6 +7379,8 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction,
7162 return action; 7379 return action;
7163 } 7380 }
7164 7381
7382 if (x_dnd_use_toplevels)
7383 x_dnd_free_toplevels ();
7165 FRAME_DISPLAY_INFO (f)->grabbed = 0; 7384 FRAME_DISPLAY_INFO (f)->grabbed = 0;
7166 7385
7167 /* Emacs can't respond to DND events inside the nested event 7386 /* Emacs can't respond to DND events inside the nested event
@@ -11292,8 +11511,22 @@ handle_one_xevent (struct x_display_info *dpyinfo,
11292 if (event->xproperty.window == dpyinfo->root_window 11511 if (event->xproperty.window == dpyinfo->root_window
11293 && (event->xproperty.atom == dpyinfo->Xatom_net_client_list_stacking 11512 && (event->xproperty.atom == dpyinfo->Xatom_net_client_list_stacking
11294 || event->xproperty.atom == dpyinfo->Xatom_net_current_desktop) 11513 || event->xproperty.atom == dpyinfo->Xatom_net_current_desktop)
11295 && x_dnd_in_progress) 11514 && x_dnd_in_progress
11296 x_dnd_update_state (dpyinfo); 11515 && dpyinfo == FRAME_DISPLAY_INFO (x_dnd_frame))
11516 {
11517 if (x_dnd_use_toplevels)
11518 {
11519 x_dnd_free_toplevels ();
11520
11521 if (x_dnd_compute_toplevels (dpyinfo))
11522 {
11523 x_dnd_free_toplevels ();
11524 x_dnd_use_toplevels = false;
11525 }
11526 }
11527
11528 x_dnd_update_state (dpyinfo);
11529 }
11297 11530
11298 x_handle_property_notify (&event->xproperty); 11531 x_handle_property_notify (&event->xproperty);
11299 xft_settings_event (dpyinfo, event); 11532 xft_settings_event (dpyinfo, event);
@@ -11464,6 +11697,19 @@ handle_one_xevent (struct x_display_info *dpyinfo,
11464 break; 11697 break;
11465 11698
11466 case UnmapNotify: 11699 case UnmapNotify:
11700 if (x_dnd_in_progress && x_dnd_use_toplevels)
11701 {
11702 for (struct x_client_list_window *tem = x_dnd_toplevels; tem;
11703 tem = tem->next)
11704 {
11705 if (tem->window == event->xmap.window)
11706 {
11707 tem->visible_p = false;
11708 break;
11709 }
11710 }
11711 }
11712
11467 /* Redo the mouse-highlight after the tooltip has gone. */ 11713 /* Redo the mouse-highlight after the tooltip has gone. */
11468 if (event->xunmap.window == tip_window) 11714 if (event->xunmap.window == tip_window)
11469 { 11715 {
@@ -11511,6 +11757,20 @@ handle_one_xevent (struct x_display_info *dpyinfo,
11511 11757
11512 if (x_dnd_in_progress) 11758 if (x_dnd_in_progress)
11513 x_dnd_update_state (dpyinfo); 11759 x_dnd_update_state (dpyinfo);
11760
11761 if (x_dnd_in_progress && x_dnd_use_toplevels)
11762 {
11763 for (struct x_client_list_window *tem = x_dnd_toplevels; tem;
11764 tem = tem->next)
11765 {
11766 if (tem->window == event->xmap.window)
11767 {
11768 tem->visible_p = true;
11769 break;
11770 }
11771 }
11772 }
11773
11514 /* We use x_top_window_to_frame because map events can 11774 /* We use x_top_window_to_frame because map events can
11515 come for sub-windows and they don't mean that the 11775 come for sub-windows and they don't mean that the
11516 frame is visible. */ 11776 frame is visible. */
@@ -12287,6 +12547,56 @@ handle_one_xevent (struct x_display_info *dpyinfo,
12287 configureEvent = next_event; 12547 configureEvent = next_event;
12288 } 12548 }
12289 12549
12550 if (x_dnd_in_progress && x_dnd_use_toplevels)
12551 {
12552 int rc, dest_x, dest_y;
12553 Window child;
12554 struct x_client_list_window *tem, *last = NULL;
12555
12556 for (tem = x_dnd_toplevels; tem; last = tem, tem = tem->next)
12557 {
12558 /* Not completely right, since the parent could be
12559 unmapped, but good enough. */
12560
12561 if (tem->window == configureEvent.xconfigure.window)
12562 {
12563 x_catch_errors (dpyinfo->display);
12564 rc = (XTranslateCoordinates (dpyinfo->display,
12565 configureEvent.xconfigure.window,
12566 dpyinfo->root_window,
12567 -configureEvent.xconfigure.border_width,
12568 -configureEvent.xconfigure.border_width,
12569 &dest_x, &dest_y, &child)
12570 && !x_had_errors_p (dpyinfo->display));
12571 x_uncatch_errors_after_check ();
12572
12573 if (rc)
12574 {
12575 tem->x = dest_x;
12576 tem->y = dest_y;
12577 tem->width = (configureEvent.xconfigure.width
12578 + configureEvent.xconfigure.border_width);
12579 tem->height = (configureEvent.xconfigure.height
12580 + configureEvent.xconfigure.border_width);
12581 }
12582 else
12583 {
12584 /* The window was probably destroyed, so get rid
12585 of it. */
12586
12587 if (!last)
12588 x_dnd_toplevels = tem->next;
12589 else
12590 last->next = tem->next;
12591
12592 xfree (tem);
12593 }
12594
12595 break;
12596 }
12597 }
12598 }
12599
12290#if defined HAVE_GTK3 && defined USE_TOOLKIT_SCROLL_BARS 12600#if defined HAVE_GTK3 && defined USE_TOOLKIT_SCROLL_BARS
12291 struct scroll_bar *bar = x_window_to_scroll_bar (dpyinfo->display, 12601 struct scroll_bar *bar = x_window_to_scroll_bar (dpyinfo->display,
12292 configureEvent.xconfigure.window, 2); 12602 configureEvent.xconfigure.window, 2);