diff options
| author | Po Lu | 2021-11-05 21:01:12 +0800 |
|---|---|---|
| committer | Lars Ingebrigtsen | 2021-11-07 02:59:41 +0100 |
| commit | f1fbf877750bb1b4741cd2b89b7d81ee1563fb97 (patch) | |
| tree | 97e1e4cd812a84beb04d8d1b8c5eec51c96310c3 /src | |
| parent | 8729ae29d8bbd6076d366ee4316f700fda7aeea3 (diff) | |
| download | emacs-f1fbf877750bb1b4741cd2b89b7d81ee1563fb97.tar.gz emacs-f1fbf877750bb1b4741cd2b89b7d81ee1563fb97.zip | |
Make the WebKit inspector available
* etc/NEWS: Document changes.
* src/xwidget.c (find_widget_at_pos)
(find_widget)
(find_widget_cb): New functions.
(struct widget_search_data): New structure.
(Fmake_xwidget): Enable web inspector for WebKit widgets.
(Fxwidget_perform_lispy_event): Use current focus instead of
hard-coded widget.
(xwidget_button_1, xwidget_button, xwidget_motion_or_crossing):
Use window at event position instead of the default widget.
Diffstat (limited to 'src')
| -rw-r--r-- | src/xwidget.c | 195 |
1 files changed, 184 insertions, 11 deletions
diff --git a/src/xwidget.c b/src/xwidget.c index 41e4accb1a7..49645b8b6fd 100644 --- a/src/xwidget.c +++ b/src/xwidget.c | |||
| @@ -82,6 +82,18 @@ webkit_decide_policy_cb (WebKitWebView *, | |||
| 82 | WebKitPolicyDecision *, | 82 | WebKitPolicyDecision *, |
| 83 | WebKitPolicyDecisionType, | 83 | WebKitPolicyDecisionType, |
| 84 | gpointer); | 84 | gpointer); |
| 85 | static GtkWidget *find_widget_at_pos (GtkWidget *, int, int, int *, int *); | ||
| 86 | |||
| 87 | struct widget_search_data | ||
| 88 | { | ||
| 89 | int x; | ||
| 90 | int y; | ||
| 91 | bool foundp; | ||
| 92 | bool first; | ||
| 93 | GtkWidget *data; | ||
| 94 | }; | ||
| 95 | |||
| 96 | static void find_widget (GtkWidget *t, struct widget_search_data *); | ||
| 85 | #endif | 97 | #endif |
| 86 | 98 | ||
| 87 | 99 | ||
| @@ -130,6 +142,7 @@ Returns the newly constructed xwidget, or nil if construction fails. */) | |||
| 130 | if (EQ (xw->type, Qwebkit)) | 142 | if (EQ (xw->type, Qwebkit)) |
| 131 | { | 143 | { |
| 132 | block_input (); | 144 | block_input (); |
| 145 | WebKitSettings *settings; | ||
| 133 | WebKitWebContext *webkit_context = webkit_web_context_get_default (); | 146 | WebKitWebContext *webkit_context = webkit_web_context_get_default (); |
| 134 | 147 | ||
| 135 | # if WEBKIT_CHECK_VERSION (2, 26, 0) | 148 | # if WEBKIT_CHECK_VERSION (2, 26, 0) |
| @@ -145,6 +158,10 @@ Returns the newly constructed xwidget, or nil if construction fails. */) | |||
| 145 | { | 158 | { |
| 146 | xw->widget_osr = webkit_web_view_new (); | 159 | xw->widget_osr = webkit_web_view_new (); |
| 147 | 160 | ||
| 161 | /* Enable the developer extras */ | ||
| 162 | settings = webkit_web_view_get_settings (WEBKIT_WEB_VIEW (xw->widget_osr)); | ||
| 163 | g_object_set (G_OBJECT (settings), "enable-developer-extras", TRUE, NULL); | ||
| 164 | |||
| 148 | /* webkitgtk uses GSubprocess which sets sigaction causing | 165 | /* webkitgtk uses GSubprocess which sets sigaction causing |
| 149 | Emacs to not catch SIGCHLD with its usual handle setup in | 166 | Emacs to not catch SIGCHLD with its usual handle setup in |
| 150 | catch_child_signal(). This resets the SIGCHLD | 167 | catch_child_signal(). This resets the SIGCHLD |
| @@ -251,9 +268,12 @@ X-Windows frame. */) | |||
| 251 | else if (FRAME_X_P (SELECTED_FRAME ())) | 268 | else if (FRAME_X_P (SELECTED_FRAME ())) |
| 252 | f = SELECTED_FRAME (); | 269 | f = SELECTED_FRAME (); |
| 253 | 270 | ||
| 254 | widget = xw->widget_osr; | ||
| 255 | |||
| 256 | #ifdef USE_GTK | 271 | #ifdef USE_GTK |
| 272 | widget = gtk_window_get_focus (GTK_WINDOW (xw->widgetwindow_osr)); | ||
| 273 | |||
| 274 | if (!widget) | ||
| 275 | widget = xw->widget_osr; | ||
| 276 | |||
| 257 | if (RANGED_FIXNUMP (0, event, INT_MAX)) | 277 | if (RANGED_FIXNUMP (0, event, INT_MAX)) |
| 258 | { | 278 | { |
| 259 | character = XFIXNUM (event); | 279 | character = XFIXNUM (event); |
| @@ -324,7 +344,7 @@ X-Windows frame. */) | |||
| 324 | if (keycode > -1) | 344 | if (keycode > -1) |
| 325 | { | 345 | { |
| 326 | /* WebKitGTK internals abuse follows. */ | 346 | /* WebKitGTK internals abuse follows. */ |
| 327 | if (EQ (xw->type, Qwebkit)) | 347 | if (WEBKIT_IS_WEB_VIEW (widget)) |
| 328 | { | 348 | { |
| 329 | /* WebKitGTK relies on an internal GtkTextView object to | 349 | /* WebKitGTK relies on an internal GtkTextView object to |
| 330 | "translate" keys such as backspace. We must find that | 350 | "translate" keys such as backspace. We must find that |
| @@ -428,18 +448,149 @@ find_suitable_keyboard (struct frame *f) | |||
| 428 | } | 448 | } |
| 429 | 449 | ||
| 430 | static void | 450 | static void |
| 451 | find_widget_cb (GtkWidget *widget, void *user) | ||
| 452 | { | ||
| 453 | find_widget (widget, user); | ||
| 454 | } | ||
| 455 | |||
| 456 | static void | ||
| 457 | find_widget (GtkWidget *widget, | ||
| 458 | struct widget_search_data *data) | ||
| 459 | { | ||
| 460 | GtkAllocation new_allocation; | ||
| 461 | GdkWindow *window; | ||
| 462 | int x_offset = 0; | ||
| 463 | int y_offset = 0; | ||
| 464 | |||
| 465 | gtk_widget_get_allocation (widget, &new_allocation); | ||
| 466 | |||
| 467 | if (gtk_widget_get_has_window (widget)) | ||
| 468 | { | ||
| 469 | new_allocation.x = 0; | ||
| 470 | new_allocation.y = 0; | ||
| 471 | } | ||
| 472 | |||
| 473 | if (gtk_widget_get_parent (widget) && !data->first) | ||
| 474 | { | ||
| 475 | window = gtk_widget_get_window (widget); | ||
| 476 | while (window != gtk_widget_get_window (gtk_widget_get_parent (widget))) | ||
| 477 | { | ||
| 478 | gint tx, ty, twidth, theight; | ||
| 479 | |||
| 480 | if (!window) | ||
| 481 | return; | ||
| 482 | |||
| 483 | twidth = gdk_window_get_width (window); | ||
| 484 | theight = gdk_window_get_height (window); | ||
| 485 | |||
| 486 | if (new_allocation.x < 0) | ||
| 487 | { | ||
| 488 | new_allocation.width += new_allocation.x; | ||
| 489 | new_allocation.x = 0; | ||
| 490 | } | ||
| 491 | |||
| 492 | if (new_allocation.y < 0) | ||
| 493 | { | ||
| 494 | new_allocation.height += new_allocation.y; | ||
| 495 | new_allocation.y = 0; | ||
| 496 | } | ||
| 497 | |||
| 498 | if (new_allocation.x + new_allocation.width > twidth) | ||
| 499 | new_allocation.width = twidth - new_allocation.x; | ||
| 500 | if (new_allocation.y + new_allocation.height > theight) | ||
| 501 | new_allocation.height = theight - new_allocation.y; | ||
| 502 | |||
| 503 | gdk_window_get_position (window, &tx, &ty); | ||
| 504 | new_allocation.x += tx; | ||
| 505 | x_offset += tx; | ||
| 506 | new_allocation.y += ty; | ||
| 507 | y_offset += ty; | ||
| 508 | |||
| 509 | window = gdk_window_get_parent (window); | ||
| 510 | } | ||
| 511 | } | ||
| 512 | |||
| 513 | if ((data->x >= new_allocation.x) && (data->y >= new_allocation.y) && | ||
| 514 | (data->x < new_allocation.x + new_allocation.width) && | ||
| 515 | (data->y < new_allocation.y + new_allocation.height)) | ||
| 516 | { | ||
| 517 | /* First, check if the drag is in a valid drop site in | ||
| 518 | * one of our children | ||
| 519 | */ | ||
| 520 | if (GTK_IS_CONTAINER (widget)) | ||
| 521 | { | ||
| 522 | struct widget_search_data new_data = *data; | ||
| 523 | |||
| 524 | new_data.x -= x_offset; | ||
| 525 | new_data.y -= y_offset; | ||
| 526 | new_data.foundp = false; | ||
| 527 | new_data.first = false; | ||
| 528 | |||
| 529 | gtk_container_forall (GTK_CONTAINER (widget), | ||
| 530 | find_widget_cb, &new_data); | ||
| 531 | |||
| 532 | data->foundp = new_data.foundp; | ||
| 533 | if (data->foundp) | ||
| 534 | data->data = new_data.data; | ||
| 535 | } | ||
| 536 | |||
| 537 | /* If not, and this widget is registered as a drop site, check to | ||
| 538 | * emit "drag_motion" to check if we are actually in | ||
| 539 | * a drop site. | ||
| 540 | */ | ||
| 541 | if (!data->foundp) | ||
| 542 | { | ||
| 543 | data->foundp = true; | ||
| 544 | data->data = widget; | ||
| 545 | } | ||
| 546 | } | ||
| 547 | } | ||
| 548 | |||
| 549 | static GtkWidget * | ||
| 550 | find_widget_at_pos (GtkWidget *w, int x, int y, | ||
| 551 | int *new_x, int *new_y) | ||
| 552 | { | ||
| 553 | struct widget_search_data data; | ||
| 554 | |||
| 555 | data.x = x; | ||
| 556 | data.y = y; | ||
| 557 | data.foundp = false; | ||
| 558 | data.first = true; | ||
| 559 | |||
| 560 | find_widget (w, &data); | ||
| 561 | |||
| 562 | if (data.foundp) | ||
| 563 | { | ||
| 564 | gtk_widget_translate_coordinates (w, data.data, x, | ||
| 565 | y, new_x, new_y); | ||
| 566 | return data.data; | ||
| 567 | } | ||
| 568 | |||
| 569 | *new_x = x; | ||
| 570 | *new_y = y; | ||
| 571 | |||
| 572 | return NULL; | ||
| 573 | } | ||
| 574 | |||
| 575 | static void | ||
| 431 | xwidget_button_1 (struct xwidget_view *view, | 576 | xwidget_button_1 (struct xwidget_view *view, |
| 432 | bool down_p, int x, int y, int button, | 577 | bool down_p, int x, int y, int button, |
| 433 | int modifier_state, Time time) | 578 | int modifier_state, Time time) |
| 434 | { | 579 | { |
| 435 | GdkEvent *xg_event = gdk_event_new (down_p ? GDK_BUTTON_PRESS : GDK_BUTTON_RELEASE); | 580 | GdkEvent *xg_event = gdk_event_new (down_p ? GDK_BUTTON_PRESS : GDK_BUTTON_RELEASE); |
| 436 | struct xwidget *model = XXWIDGET (view->model); | 581 | struct xwidget *model = XXWIDGET (view->model); |
| 582 | GtkWidget *target; | ||
| 437 | 583 | ||
| 438 | /* X and Y should be relative to the origin of view->wdesc. */ | 584 | /* X and Y should be relative to the origin of view->wdesc. */ |
| 439 | x += view->clip_left; | 585 | x += view->clip_left; |
| 440 | y += view->clip_top; | 586 | y += view->clip_top; |
| 441 | 587 | ||
| 442 | xg_event->any.window = gtk_widget_get_window (model->widget_osr); | 588 | target = find_widget_at_pos (model->widgetwindow_osr, x, y, &x, &y); |
| 589 | |||
| 590 | if (!target) | ||
| 591 | target = model->widget_osr; | ||
| 592 | |||
| 593 | xg_event->any.window = gtk_widget_get_window (target); | ||
| 443 | g_object_ref (xg_event->any.window); /* The window will be unrefed | 594 | g_object_ref (xg_event->any.window); /* The window will be unrefed |
| 444 | later by gdk_event_free. */ | 595 | later by gdk_event_free. */ |
| 445 | 596 | ||
| @@ -467,8 +618,17 @@ xwidget_button (struct xwidget_view *view, | |||
| 467 | { | 618 | { |
| 468 | GdkEvent *xg_event = gdk_event_new (GDK_SCROLL); | 619 | GdkEvent *xg_event = gdk_event_new (GDK_SCROLL); |
| 469 | struct xwidget *model = XXWIDGET (view->model); | 620 | struct xwidget *model = XXWIDGET (view->model); |
| 621 | GtkWidget *target; | ||
| 622 | |||
| 623 | x += view->clip_left; | ||
| 624 | y += view->clip_top; | ||
| 470 | 625 | ||
| 471 | xg_event->any.window = gtk_widget_get_window (model->widget_osr); | 626 | target = find_widget_at_pos (model->widgetwindow_osr, x, y, &x, &y); |
| 627 | |||
| 628 | if (!target) | ||
| 629 | target = model->widget_osr; | ||
| 630 | |||
| 631 | xg_event->any.window = gtk_widget_get_window (target); | ||
| 472 | g_object_ref (xg_event->any.window); /* The window will be unrefed | 632 | g_object_ref (xg_event->any.window); /* The window will be unrefed |
| 473 | later by gdk_event_free. */ | 633 | later by gdk_event_free. */ |
| 474 | if (button == 4) | 634 | if (button == 4) |
| @@ -504,15 +664,28 @@ xwidget_motion_or_crossing (struct xwidget_view *view, const XEvent *event) | |||
| 504 | (event->type == LeaveNotify ? GDK_LEAVE_NOTIFY : | 664 | (event->type == LeaveNotify ? GDK_LEAVE_NOTIFY : |
| 505 | GDK_ENTER_NOTIFY)); | 665 | GDK_ENTER_NOTIFY)); |
| 506 | struct xwidget *model = XXWIDGET (view->model); | 666 | struct xwidget *model = XXWIDGET (view->model); |
| 507 | 667 | int x; | |
| 508 | xg_event->any.window = gtk_widget_get_window (model->widget_osr); | 668 | int y; |
| 669 | GtkWidget *target = find_widget_at_pos (model->widgetwindow_osr, | ||
| 670 | (event->type == MotionNotify | ||
| 671 | ? event->xmotion.x + view->clip_left | ||
| 672 | : event->xmotion.y + view->clip_top), | ||
| 673 | (event->type == MotionNotify | ||
| 674 | ? event->xmotion.y + view->clip_left | ||
| 675 | : event->xcrossing.y + view->clip_top), | ||
| 676 | &x, &y); | ||
| 677 | |||
| 678 | if (!target) | ||
| 679 | target = model->widgetwindow_osr; | ||
| 680 | |||
| 681 | xg_event->any.window = gtk_widget_get_window (target); | ||
| 509 | g_object_ref (xg_event->any.window); /* The window will be unrefed | 682 | g_object_ref (xg_event->any.window); /* The window will be unrefed |
| 510 | later by gdk_event_free. */ | 683 | later by gdk_event_free. */ |
| 511 | 684 | ||
| 512 | if (event->type == MotionNotify) | 685 | if (event->type == MotionNotify) |
| 513 | { | 686 | { |
| 514 | xg_event->motion.x = event->xmotion.x + view->clip_left; | 687 | xg_event->motion.x = x; |
| 515 | xg_event->motion.y = event->xmotion.y + view->clip_top; | 688 | xg_event->motion.y = y; |
| 516 | xg_event->motion.x_root = event->xmotion.x_root; | 689 | xg_event->motion.x_root = event->xmotion.x_root; |
| 517 | xg_event->motion.y_root = event->xmotion.y_root; | 690 | xg_event->motion.y_root = event->xmotion.y_root; |
| 518 | xg_event->motion.time = event->xmotion.time; | 691 | xg_event->motion.time = event->xmotion.time; |
| @@ -523,8 +696,8 @@ xwidget_motion_or_crossing (struct xwidget_view *view, const XEvent *event) | |||
| 523 | { | 696 | { |
| 524 | xg_event->crossing.detail = min (5, event->xcrossing.detail); | 697 | xg_event->crossing.detail = min (5, event->xcrossing.detail); |
| 525 | xg_event->crossing.time = event->xcrossing.time; | 698 | xg_event->crossing.time = event->xcrossing.time; |
| 526 | xg_event->crossing.x = event->xcrossing.x + view->clip_left; | 699 | xg_event->crossing.x = x; |
| 527 | xg_event->crossing.y = event->xcrossing.y + view->clip_top; | 700 | xg_event->crossing.y = y; |
| 528 | xg_event->crossing.x_root = event->xcrossing.x_root; | 701 | xg_event->crossing.x_root = event->xcrossing.x_root; |
| 529 | xg_event->crossing.y_root = event->xcrossing.y_root; | 702 | xg_event->crossing.y_root = event->xcrossing.y_root; |
| 530 | gdk_event_set_device (xg_event, find_suitable_pointer (view->frame)); | 703 | gdk_event_set_device (xg_event, find_suitable_pointer (view->frame)); |