aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPo Lu2022-01-27 21:36:52 +0800
committerPo Lu2022-01-27 21:38:07 +0800
commit0991e8686cd90a7678346b7608c438fcb7e06bc6 (patch)
tree5c5ff468fc7d4acdc3e23a8cdd5d267bd4e1646c /src
parent63255de48b498a8fab4cec5da244998f1ed23f8e (diff)
downloademacs-0991e8686cd90a7678346b7608c438fcb7e06bc6.tar.gz
emacs-0991e8686cd90a7678346b7608c438fcb7e06bc6.zip
Improve xwidget window ancestry calculations
* src/xwidget.c (xw_find_common_ancestor): (xw_notify_virtual_upwards_until) (xw_notify_virtual_downwards_until): New functions. (xw_maybe_synthesize_crossing): Synthesize virtual events like GTK does for non-linear changes.
Diffstat (limited to 'src')
-rw-r--r--src/xwidget.c184
1 files changed, 177 insertions, 7 deletions
diff --git a/src/xwidget.c b/src/xwidget.c
index c42d1609d7a..175a289a007 100644
--- a/src/xwidget.c
+++ b/src/xwidget.c
@@ -1416,16 +1416,153 @@ window_coords_from_toplevel (GdkWindow *window, GdkWindow *toplevel,
1416 *out_y = y_out; 1416 *out_y = y_out;
1417} 1417}
1418 1418
1419static GdkWindow *
1420xw_find_common_ancestor (GdkWindow *window,
1421 GdkWindow *other,
1422 GdkWindow *toplevel)
1423{
1424 GdkWindow *tem;
1425 GList *l1 = NULL;
1426 GList *l2 = NULL;
1427 GList *i1, *i2;
1428
1429 tem = window;
1430 while (tem && tem != toplevel)
1431 {
1432 l1 = g_list_prepend (l1, tem);
1433 tem = gdk_window_get_parent (tem);
1434 }
1435
1436 tem = other;
1437 while (tem && tem != toplevel)
1438 {
1439 l2 = g_list_prepend (l2, tem);
1440 tem = gdk_window_get_parent (tem);
1441 }
1442
1443 tem = NULL;
1444 i1 = l1;
1445 i2 = l2;
1446
1447 while (i1 && i2 && (i1->data == i2->data))
1448 {
1449 tem = i1->data;
1450 i1 = i1->next;
1451 i2 = i2->next;
1452 }
1453
1454 g_list_free (l1);
1455 g_list_free (l2);
1456
1457 return tem;
1458}
1459
1460static void
1461xw_notify_virtual_upwards_until (struct xwidget_view *xv,
1462 GdkWindow *window,
1463 GdkWindow *until,
1464 GdkWindow *toplevel,
1465 unsigned int state,
1466 int x, int y, Time time,
1467 GdkEventType type,
1468 bool nonlinear_p)
1469{
1470 GdkEvent *xg_event;
1471 GdkWindow *tem;
1472 int cx, cy;
1473
1474 for (tem = gdk_window_get_parent (window);
1475 tem && (tem != until);
1476 tem = gdk_window_get_parent (tem))
1477 {
1478 xg_event = gdk_event_new (type);
1479
1480 gdk_event_set_device (xg_event, find_suitable_pointer (xv->frame));
1481 window_coords_from_toplevel (tem, toplevel, x, y, &cx, &cy);
1482 xg_event->crossing.x = cx;
1483 xg_event->crossing.y = cy;
1484 xg_event->crossing.time = time;
1485 xg_event->crossing.focus = FALSE;
1486 xg_event->crossing.detail = (nonlinear_p
1487 ? GDK_NOTIFY_NONLINEAR_VIRTUAL
1488 : GDK_NOTIFY_VIRTUAL);
1489 xg_event->crossing.mode = GDK_CROSSING_NORMAL;
1490 xg_event->crossing.window = g_object_ref (tem);
1491
1492 gtk_main_do_event (xg_event);
1493 gdk_event_free (xg_event);
1494 }
1495}
1496
1497static void
1498xw_notify_virtual_downwards_until (struct xwidget_view *xv,
1499 GdkWindow *window,
1500 GdkWindow *until,
1501 GdkWindow *toplevel,
1502 unsigned int state,
1503 int x, int y, Time time,
1504 GdkEventType type,
1505 bool nonlinear_p)
1506{
1507 GdkEvent *xg_event;
1508 GdkWindow *tem;
1509 int cx, cy;
1510 GList *path = NULL, *it;
1511
1512 tem = gdk_window_get_parent (window);
1513
1514 while (tem && tem != until)
1515 {
1516 path = g_list_prepend (path, tem);
1517 tem = gdk_window_get_parent (tem);
1518 }
1519
1520 for (it = path; it; it = it->next)
1521 {
1522 tem = it->data;
1523 xg_event = gdk_event_new (type);
1524
1525 gdk_event_set_device (xg_event, find_suitable_pointer (xv->frame));
1526 window_coords_from_toplevel (tem, toplevel, x, y, &cx, &cy);
1527 xg_event->crossing.x = cx;
1528 xg_event->crossing.y = cy;
1529 xg_event->crossing.time = time;
1530 xg_event->crossing.focus = FALSE;
1531 xg_event->crossing.detail = (nonlinear_p
1532 ? GDK_NOTIFY_NONLINEAR_VIRTUAL
1533 : GDK_NOTIFY_VIRTUAL);
1534 xg_event->crossing.mode = GDK_CROSSING_NORMAL;
1535 xg_event->crossing.window = g_object_ref (tem);
1536
1537 gtk_main_do_event (xg_event);
1538 gdk_event_free (xg_event);
1539 }
1540
1541 g_list_free (path);
1542}
1543
1419static bool 1544static bool
1420xw_maybe_synthesize_crossing (struct xwidget_view *view, 1545xw_maybe_synthesize_crossing (struct xwidget_view *view,
1421 GdkWindow *current_window, 1546 GdkWindow *current_window,
1422 int x, int y, int crossing, 1547 int x, int y, int crossing,
1423 Time time, unsigned int state) 1548 Time time, unsigned int state)
1424{ 1549{
1425 GdkWindow *last_crossing; 1550 GdkWindow *last_crossing, *toplevel, *ancestor;
1426 GdkEvent *xg_event; 1551 GdkEvent *xg_event;
1427 GdkWindow *toplevel;
1428 int cx, cy; 1552 int cx, cy;
1553 bool nonlinear_p;
1554
1555 toplevel = gtk_widget_get_window (XXWIDGET (view->model)->widgetwindow_osr);
1556
1557 if (crossing == XW_CROSSING_LEFT
1558 && (view->last_crossing_window
1559 && !gdk_window_is_destroyed (view->last_crossing_window)))
1560 {
1561 xw_notify_virtual_upwards_until (view, view->last_crossing_window,
1562 toplevel, toplevel,
1563 state, x, y, time,
1564 GDK_LEAVE_NOTIFY, false);
1565 }
1429 1566
1430 if (view->last_crossing_window 1567 if (view->last_crossing_window
1431 && (gdk_window_is_destroyed (view->last_crossing_window) 1568 && (gdk_window_is_destroyed (view->last_crossing_window)
@@ -1437,15 +1574,33 @@ xw_maybe_synthesize_crossing (struct xwidget_view *view,
1437 if (!last_crossing) 1574 if (!last_crossing)
1438 { 1575 {
1439 view->last_crossing_window = g_object_ref (current_window); 1576 view->last_crossing_window = g_object_ref (current_window);
1577
1578 xw_notify_virtual_downwards_until (view, current_window,
1579 toplevel, toplevel,
1580 state, x, y, time,
1581 GDK_ENTER_NOTIFY,
1582 false);
1440 return false; 1583 return false;
1441 } 1584 }
1442 1585
1443 toplevel = gtk_widget_get_window (XXWIDGET (view->model)->widgetwindow_osr);
1444
1445 if (last_crossing != current_window) 1586 if (last_crossing != current_window)
1446 { 1587 {
1447 view->last_crossing_window = g_object_ref (current_window); 1588 view->last_crossing_window = g_object_ref (current_window);
1448 1589
1590 ancestor = xw_find_common_ancestor (last_crossing, current_window, toplevel);
1591
1592 if (!ancestor)
1593 emacs_abort ();
1594
1595 nonlinear_p = (last_crossing != ancestor) && (current_window != ancestor);
1596
1597 if (nonlinear_p || (last_crossing != ancestor))
1598 xw_notify_virtual_upwards_until (view, last_crossing,
1599 ancestor, toplevel,
1600 state, x, y, time,
1601 GDK_LEAVE_NOTIFY,
1602 nonlinear_p);
1603
1449 xg_event = gdk_event_new (GDK_LEAVE_NOTIFY); 1604 xg_event = gdk_event_new (GDK_LEAVE_NOTIFY);
1450 gdk_event_set_device (xg_event, find_suitable_pointer (view->frame)); 1605 gdk_event_set_device (xg_event, find_suitable_pointer (view->frame));
1451 window_coords_from_toplevel (last_crossing, toplevel, 1606 window_coords_from_toplevel (last_crossing, toplevel,
@@ -1455,14 +1610,25 @@ xw_maybe_synthesize_crossing (struct xwidget_view *view,
1455 xg_event->crossing.time = time; 1610 xg_event->crossing.time = time;
1456 xg_event->crossing.focus = FALSE; 1611 xg_event->crossing.focus = FALSE;
1457 xg_event->crossing.state = state; 1612 xg_event->crossing.state = state;
1458 /* TODO: actually calculate the event detail and mode. */ 1613 /* TODO: actually calculate the event mode. */
1459 xg_event->crossing.detail = GDK_NOTIFY_NONLINEAR; 1614 xg_event->crossing.detail = (nonlinear_p
1615 ? GDK_NOTIFY_NONLINEAR
1616 : (last_crossing == ancestor
1617 ? GDK_NOTIFY_INFERIOR
1618 : GDK_NOTIFY_ANCESTOR));
1460 xg_event->crossing.mode = GDK_CROSSING_NORMAL; 1619 xg_event->crossing.mode = GDK_CROSSING_NORMAL;
1461 xg_event->crossing.window = g_object_ref (last_crossing); 1620 xg_event->crossing.window = g_object_ref (last_crossing);
1462 1621
1463 gtk_main_do_event (xg_event); 1622 gtk_main_do_event (xg_event);
1464 gdk_event_free (xg_event); 1623 gdk_event_free (xg_event);
1465 1624
1625 if (nonlinear_p || (current_window != ancestor))
1626 xw_notify_virtual_downwards_until (view, current_window,
1627 ancestor, toplevel,
1628 state, x, y, time,
1629 GDK_ENTER_NOTIFY,
1630 nonlinear_p);
1631
1466 xg_event = gdk_event_new (GDK_ENTER_NOTIFY); 1632 xg_event = gdk_event_new (GDK_ENTER_NOTIFY);
1467 gdk_event_set_device (xg_event, find_suitable_pointer (view->frame)); 1633 gdk_event_set_device (xg_event, find_suitable_pointer (view->frame));
1468 window_coords_from_toplevel (current_window, toplevel, 1634 window_coords_from_toplevel (current_window, toplevel,
@@ -1472,7 +1638,11 @@ xw_maybe_synthesize_crossing (struct xwidget_view *view,
1472 xg_event->crossing.time = time; 1638 xg_event->crossing.time = time;
1473 xg_event->crossing.focus = FALSE; 1639 xg_event->crossing.focus = FALSE;
1474 xg_event->crossing.state = state; 1640 xg_event->crossing.state = state;
1475 xg_event->crossing.detail = GDK_NOTIFY_NONLINEAR; 1641 xg_event->crossing.detail = (nonlinear_p
1642 ? GDK_NOTIFY_NONLINEAR
1643 : (current_window == ancestor
1644 ? GDK_NOTIFY_INFERIOR
1645 : GDK_NOTIFY_ANCESTOR));
1476 xg_event->crossing.mode = GDK_CROSSING_NORMAL; 1646 xg_event->crossing.mode = GDK_CROSSING_NORMAL;
1477 xg_event->crossing.window = g_object_ref (current_window); 1647 xg_event->crossing.window = g_object_ref (current_window);
1478 1648