Merge branch 'blender-v2.83-release'
authorCampbell Barton <ideasman42@gmail.com>
Wed, 20 May 2020 12:16:42 +0000 (22:16 +1000)
committerCampbell Barton <ideasman42@gmail.com>
Wed, 20 May 2020 12:16:42 +0000 (22:16 +1000)
1  2 
source/blender/editors/include/UI_interface.h
source/blender/editors/interface/interface_handlers.c
source/blender/windowmanager/intern/wm_event_system.c

index 8b7b0430765f00f6eac3dc84a4a28b3e72566830,b8413fc86f98a634ea1549b2fa0375d18f171313..3ad1608b47b205fd209f15018688dd4f4fd80fd6
@@@ -250,8 -250,6 +250,8 @@@ enum 
    UI_BUT_TEXT_RIGHT = 1 << 3,
    /** Prevent the button to show any tooltip. */
    UI_BUT_NO_TOOLTIP = 1 << 4,
 +  /** Do not add the usual horizontal padding for text drawing. */
 +  UI_BUT_NO_TEXT_PADDING = 1 << 5,
  
    /* Button align flag, for drawing groups together.
     * Used in 'uiBlock.flag', take care! */
@@@ -502,24 -500,15 +502,24 @@@ typedef void (*uiButHandleRenameFunc)(s
  typedef void (*uiButHandleNFunc)(struct bContext *C, void *argN, void *arg2);
  typedef void (*uiButHandleHoldFunc)(struct bContext *C, struct ARegion *butregion, uiBut *but);
  typedef int (*uiButCompleteFunc)(struct bContext *C, char *str, void *arg);
 -typedef struct ARegion *(*uiButSearchCreateFunc)(struct bContext *C,
 -                                                 struct ARegion *butregion,
 -                                                 uiBut *but);
 -typedef void (*uiButSearchFunc)(const struct bContext *C,
 -                                void *arg,
 -                                const char *str,
 -                                uiSearchItems *items);
  
 -typedef void (*uiButSearchArgFreeFunc)(void *arg);
 +/* Search types. */
 +typedef struct ARegion *(*uiButSearchCreateFn)(struct bContext *C,
 +                                               struct ARegion *butregion,
 +                                               uiBut *but);
 +typedef void (*uiButSearchUpdateFn)(const struct bContext *C,
 +                                    void *arg,
 +                                    const char *str,
 +                                    uiSearchItems *items);
 +typedef void (*uiButSearchArgFreeFn)(void *arg);
 +typedef bool (*uiButSearchContextMenuFn)(struct bContext *C,
 +                                         void *arg,
 +                                         void *active,
 +                                         const struct wmEvent *event);
 +typedef struct ARegion *(*uiButSearchTooltipFn)(struct bContext *C,
 +                                                struct ARegion *region,
 +                                                void *arg,
 +                                                void *active);
  
  /* Must return allocated string. */
  typedef char *(*uiButToolTipFunc)(struct bContext *C, void *argN, const char *tip);
@@@ -630,7 -619,8 +630,7 @@@ void UI_popup_block_invoke_ex(struct bC
                                uiBlockCreateFunc func,
                                void *arg,
                                void (*arg_free)(void *arg),
 -                              const char *opname,
 -                              int opcontext);
 +                              bool can_refresh);
  void UI_popup_block_ex(struct bContext *C,
                         uiBlockCreateFunc func,
                         uiBlockHandleFunc popup_func,
@@@ -1580,25 -1570,21 +1580,25 @@@ eAutoPropButsReturn uiDefAutoButsRNA(ui
  
  /* use inside searchfunc to add items */
  bool UI_search_item_add(uiSearchItems *items, const char *name, void *poin, int iconid, int state);
 -/* bfunc gets search item *poin as arg2, or if NULL the old string */
  void UI_but_func_search_set(uiBut *but,
 -                            uiButSearchCreateFunc cfunc,
 -                            uiButSearchFunc sfunc,
 +                            uiButSearchCreateFn search_create_fn,
 +                            uiButSearchUpdateFn search_update_fn,
                              void *arg,
 -                            uiButSearchArgFreeFunc search_arg_free_func,
 -                            uiButHandleFunc bfunc,
 -                            const char *search_sep_string,
 +                            uiButSearchArgFreeFn search_arg_free_fn,
 +                            uiButHandleFunc search_exec_fn,
                              void *active);
 +void UI_but_func_search_set_context_menu(uiBut *but, uiButSearchContextMenuFn context_menu_fn);
 +void UI_but_func_search_set_tooltip(uiBut *but, uiButSearchTooltipFn tooltip_fn);
 +void UI_but_func_search_set_sep_string(uiBut *but, const char *search_sep_string);
 +
  /* height in pixels, it's using hardcoded values still */
  int UI_searchbox_size_y(void);
  int UI_searchbox_size_x(void);
  /* check if a string is in an existing search box */
  int UI_search_items_find_index(uiSearchItems *items, const char *name);
  
 +void UI_but_node_link_set(uiBut *but, struct bNodeSocket *socket, const float draw_color[4]);
 +
  void UI_block_func_handle_set(uiBlock *block, uiBlockHandleFunc func, void *arg);
  void UI_block_func_butmenu_set(uiBlock *block, uiMenuHandleFunc func, void *arg);
  void UI_block_func_set(uiBlock *block, uiButHandleFunc func, void *arg1, void *arg2);
@@@ -1682,7 -1668,6 +1682,7 @@@ void UI_panel_end(const struct ScrArea 
  void UI_panels_scale(struct ARegion *region, float new_width);
  void UI_panel_label_offset(struct uiBlock *block, int *r_x, int *r_y);
  int UI_panel_size_y(const struct Panel *panel);
 +bool UI_panel_is_dragging(const struct Panel *panel);
  
  bool UI_panel_category_is_visible(const struct ARegion *region);
  void UI_panel_category_add(struct ARegion *region, const char *name);
@@@ -1787,10 -1772,6 +1787,10 @@@ enum 
    UI_ITEM_O_DEPRESS = 1 << 10,
    UI_ITEM_R_COMPACT = 1 << 11,
    UI_ITEM_R_CHECKBOX_INVERT = 1 << 12,
 +  /** Don't add a real decorator item, just blank space. */
 +  UI_ITEM_R_FORCE_BLANK_DECORATE = 1 << 13,
 +  /* Even create the property split layout if there's no name to show there. */
 +  UI_ITEM_R_SPLIT_EMPTY_NAME = 1 << 14,
  };
  
  #define UI_HEADER_OFFSET ((void)0, 0.4f * UI_UNIT_X)
@@@ -1801,9 -1782,6 +1801,9 @@@ enum 
    UI_TEMPLATE_OP_PROPS_SHOW_EMPTY = 1 << 1,
    UI_TEMPLATE_OP_PROPS_COMPACT = 1 << 2,
    UI_TEMPLATE_OP_PROPS_HIDE_ADVANCED = 1 << 3,
 +  /* Disable property split for the default layout (custom ui callbacks still have full control
 +   * over the layout and can enable it). */
 +  UI_TEMPLATE_OP_PROPS_NO_SPLIT_LAYOUT = 1 << 4,
  };
  
  /* used for transp checkers */
@@@ -1891,9 -1869,7 +1891,9 @@@ bool uiLayoutGetPropDecorate(uiLayout *
  
  /* layout specifiers */
  uiLayout *uiLayoutRow(uiLayout *layout, bool align);
 +uiLayout *uiLayoutRowWithHeading(uiLayout *layout, bool align, const char *heading);
  uiLayout *uiLayoutColumn(uiLayout *layout, bool align);
 +uiLayout *uiLayoutColumnWithHeading(uiLayout *layout, bool align, const char *heading);
  uiLayout *uiLayoutColumnFlow(uiLayout *layout, int number, bool align);
  uiLayout *uiLayoutGridFlow(uiLayout *layout,
                             bool row_major,
@@@ -2068,11 -2044,11 +2068,11 @@@ void uiTemplateOperatorSearch(uiLayout 
  void UI_but_func_menu_search(uiBut *but);
  void uiTemplateMenuSearch(uiLayout *layout);
  
 -eAutoPropButsReturn uiTemplateOperatorPropertyButs(const struct bContext *C,
 -                                                   uiLayout *layout,
 -                                                   struct wmOperator *op,
 -                                                   const eButLabelAlign label_align,
 -                                                   const short flag);
 +void uiTemplateOperatorPropertyButs(const struct bContext *C,
 +                                    uiLayout *layout,
 +                                    struct wmOperator *op,
 +                                    eButLabelAlign label_align,
 +                                    short flag);
  void uiTemplateHeader3D_mode(uiLayout *layout, struct bContext *C);
  void uiTemplateEditModeSelection(uiLayout *layout, struct bContext *C);
  void uiTemplateReportsBanner(uiLayout *layout, struct bContext *C);
@@@ -2112,7 -2088,6 +2112,7 @@@ void uiTemplateList(uiLayout *layout
                      bool sort_reverse,
                      bool sort_lock);
  void uiTemplateNodeLink(uiLayout *layout,
 +                        struct bContext *C,
                          struct bNodeTree *ntree,
                          struct bNode *node,
                          struct bNodeSocket *input);
@@@ -2322,14 -2297,6 +2322,14 @@@ void uiItemsFullEnumO_items(uiLayout *l
                              const EnumPropertyItem *item_array,
                              int totitem);
  
 +typedef struct uiPropertySplitWrapper {
 +  uiLayout *label_column;
 +  uiLayout *property_row;
 +  uiLayout *decorate_column;
 +} uiPropertySplitWrapper;
 +
 +uiPropertySplitWrapper uiItemPropertySplitWrapperCreate(uiLayout *parent_layout);
 +
  void uiItemL(uiLayout *layout, const char *name, int icon); /* label */
  void uiItemL_ex(
      uiLayout *layout, const char *name, int icon, const bool highlight, const bool redalert);
@@@ -2341,9 -2308,6 +2341,9 @@@ void uiItemM_ptr(uiLayout *layout, stru
  void uiItemM(uiLayout *layout, const char *menuname, const char *name, int icon);
  /* menu contents */
  void uiItemMContents(uiLayout *layout, const char *menuname);
 +/* Decorators */
 +void uiItemDecoratorR_prop(uiLayout *layout, PointerRNA *ptr, PropertyRNA *prop, int index);
 +void uiItemDecoratorR(uiLayout *layout, PointerRNA *ptr, const char *propname, int index);
  /* value */
  void uiItemV(uiLayout *layout, const char *name, int icon, int argval);
  /* separator */
@@@ -2411,12 -2375,13 +2411,14 @@@ bool UI_context_copy_to_selected_list(s
  
  /* Helpers for Operators */
  uiBut *UI_context_active_but_get(const struct bContext *C);
 +uiBut *UI_context_active_but_get_respect_menu(const struct bContext *C);
  uiBut *UI_context_active_but_prop_get(const struct bContext *C,
                                        struct PointerRNA *r_ptr,
                                        struct PropertyRNA **r_prop,
                                        int *r_index);
  void UI_context_active_but_prop_handle(struct bContext *C);
+ void UI_context_active_but_clear(struct bContext *C, struct wmWindow *win, struct ARegion *region);
  struct wmOperator *UI_context_active_operator_get(const struct bContext *C);
  void UI_context_update_anim_flag(const struct bContext *C);
  void UI_context_active_but_prop_get_filebrowser(const struct bContext *C,
index ebde1d54c07268a558fec3d9d655c4ff3417a283,518efd79f1693bc06ea1c8570ca5170dfc47d07c..6db21ea93a55c6a752bb74249726ddb69e82f83e
@@@ -381,9 -381,6 +381,9 @@@ typedef struct uiHandleButtonData 
    uiSelectContextStore select_others;
  #endif
  
 +  /* Text field undo. */
 +  struct uiUndoStack_Text *undo_stack_text;
 +
    /* post activate */
    uiButtonActivateType posttype;
    uiBut *postbut;
@@@ -420,7 -417,7 +420,7 @@@ typedef struct uiAfterFunc 
    PropertyRNA *rnaprop;
  
    void *search_arg;
 -  uiButSearchArgFreeFunc search_arg_free_func;
 +  uiButSearchArgFreeFn search_arg_free_fn;
  
    bContextStore *context;
  
@@@ -756,12 -753,10 +756,12 @@@ static void ui_apply_but_func(bContext 
      after->rnapoin = but->rnapoin;
      after->rnaprop = but->rnaprop;
  
 -    after->search_arg_free_func = but->search_arg_free_func;
 -    after->search_arg = but->search_arg;
 -    but->search_arg_free_func = NULL;
 -    but->search_arg = NULL;
 +    if (but->search != NULL) {
 +      after->search_arg_free_fn = but->search->arg_free_fn;
 +      after->search_arg = but->search->arg;
 +      but->search->arg_free_fn = NULL;
 +      but->search->arg = NULL;
 +    }
  
      if (but->context) {
        after->context = CTX_store_copy(but->context);
@@@ -929,8 -924,8 +929,8 @@@ static void ui_apply_but_funcs_after(bC
        MEM_freeN(after.rename_orig);
      }
  
 -    if (after.search_arg_free_func) {
 -      after.search_arg_free_func(after.search_arg);
 +    if (after.search_arg_free_fn) {
 +      after.search_arg_free_fn(after.search_arg);
      }
  
      ui_afterfunc_update_preferences_dirty(&after);
@@@ -2853,23 -2848,6 +2853,23 @@@ static bool ui_textedit_delete_selectio
    return changed;
  }
  
 +static bool ui_textedit_set_cursor_pos_foreach_glyph(const char *UNUSED(str),
 +                                                     const size_t str_step_ofs,
 +                                                     const rcti *glyph_step_bounds,
 +                                                     const int UNUSED(glyph_advance_x),
 +                                                     const rctf *glyph_bounds,
 +                                                     const int UNUSED(glyph_bearing[2]),
 +                                                     void *user_data)
 +{
 +  int *cursor_data = user_data;
 +  float center = glyph_step_bounds->xmin + (BLI_rctf_size_x(glyph_bounds) / 2.0f);
 +  if (cursor_data[0] < center) {
 +    cursor_data[1] = str_step_ofs;
 +    return false;
 +  }
 +  return true;
 +}
 +
  /**
   * \param x: Screen space cursor location - #wmEvent.x
   *
@@@ -2905,7 -2883,8 +2905,7 @@@ static void ui_textedit_set_cursor_pos(
        startx += UI_DPI_ICON_SIZE / aspect;
      }
    }
 -  /* But this extra .05 makes clicks in between characters feel nicer. */
 -  startx += ((UI_TEXT_MARGIN_X + 0.05f) * U.widget_unit) / aspect;
 +  startx += (UI_TEXT_MARGIN_X * U.widget_unit) / aspect;
  
    /* mouse dragged outside the widget to the left */
    if (x < startx) {
      but->pos = but->ofs;
    }
    /* mouse inside the widget, mouse coords mapped in widget space */
 -  else { /* (x >= startx) */
 -    int pos_i;
 -
 -    /* keep track of previous distance from the cursor to the char */
 -    float cdist, cdist_prev = 0.0f;
 -    short pos_prev;
 -
 -    str_last = &str[strlen(str)];
 -
 -    but->pos = pos_prev = ((str_last - str) - but->ofs);
 -
 -    while (true) {
 -      cdist = startx + BLF_width(fstyle.uifont_id, str + but->ofs, (str_last - str) - but->ofs);
 -
 -      /* check if position is found */
 -      if (cdist < x) {
 -        /* check is previous location was in fact closer */
 -        if ((x - cdist) > (cdist_prev - x)) {
 -          but->pos = pos_prev;
 -        }
 -        break;
 -      }
 -      cdist_prev = cdist;
 -      pos_prev = but->pos;
 -      /* done with tricky distance checks */
 -
 -      pos_i = but->pos;
 -      if (but->pos <= 0) {
 -        break;
 -      }
 -      if (BLI_str_cursor_step_prev_utf8(str + but->ofs, but->ofs, &pos_i)) {
 -        but->pos = pos_i;
 -        str_last = &str[but->pos + but->ofs];
 -      }
 -      else {
 -        break; /* unlikely but possible */
 -      }
 -    }
 -    but->pos += but->ofs;
 -    if (but->pos < 0) {
 -      but->pos = 0;
 -    }
 +  else {
 +    str_last = &str[but->ofs];
 +    const int str_last_len = strlen(str_last);
 +    int x_pos = (int)(x - startx);
 +    int glyph_data[2] = {
 +        x_pos, /* horizontal position to test. */
 +        -1,    /* Write the character offset here. */
 +    };
 +    BLF_boundbox_foreach_glyph(fstyle.uifont_id,
 +                               str + but->ofs,
 +                               INT_MAX,
 +                               ui_textedit_set_cursor_pos_foreach_glyph,
 +                               glyph_data);
 +    /* If value untouched then we are to the right. */
 +    if (glyph_data[1] == -1) {
 +      glyph_data[1] = str_last_len;
 +    }
 +    but->pos = glyph_data[1] + but->ofs;
    }
  
    if (fstyle.kerning == 1) {
@@@ -3311,13 -3314,9 +3311,13 @@@ static void ui_textedit_begin(bContext 
    but->selsta = 0;
    but->selend = len;
  
 +  /* Initialize undo history tracking. */
 +  data->undo_stack_text = ui_textedit_undo_stack_create();
 +  ui_textedit_undo_push(data->undo_stack_text, but->editstr, but->pos);
 +
    /* optional searchbox */
    if (but->type == UI_BTYPE_SEARCH_MENU) {
 -    data->searchbox = but->search_create_func(C, data->region, but);
 +    data->searchbox = but->search->create_fn(C, data->region, but);
      ui_searchbox_update(C, data->searchbox, but, true); /* true = reset */
    }
  
@@@ -3357,9 -3356,6 +3357,9 @@@ static void ui_textedit_end(bContext *C
  
            /* ensure menu (popup) too is closed! */
            data->escapecancel = true;
 +
 +          WM_reportf(RPT_ERROR, "Failed to find '%s'", but->editstr);
 +          WM_report_banner_show();
          }
        }
  
  
    WM_cursor_modal_restore(win);
  
 +  /* Free text undo history text blocks. */
 +  ui_textedit_undo_stack_destroy(data->undo_stack_text);
 +  data->undo_stack_text = NULL;
 +
  #ifdef WITH_INPUT_IME
    if (win->ime_data) {
      ui_textedit_ime_end(win, but);
@@@ -3456,7 -3448,7 +3456,7 @@@ static void ui_do_but_textedit
      bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event)
  {
    int retval = WM_UI_HANDLER_CONTINUE;
 -  bool changed = false, inbox = false, update = false;
 +  bool changed = false, inbox = false, update = false, skip_undo_push = false;
  
  #ifdef WITH_INPUT_IME
    wmWindow *win = CTX_wm_window(C);
            /* pass */
          }
          else {
 -          ui_searchbox_event(C, data->searchbox, but, event);
 +          ui_searchbox_event(C, data->searchbox, but, data->region, event);
          }
  #else
          ui_searchbox_event(C, data->searchbox, but, event);
      case RIGHTMOUSE:
      case EVT_ESCKEY:
        if (event->val == KM_PRESS) {
 +        /* Support search context menu. */
 +        if (event->type == RIGHTMOUSE) {
 +          if (data->searchbox) {
 +            if (ui_searchbox_event(C, data->searchbox, but, data->region, event)) {
 +              /* Only break if the event was handled. */
 +              break;
 +            }
 +          }
 +        }
 +
  #ifdef WITH_INPUT_IME
          /* skips button handling since it is not wanted */
          if (is_ime_composing) {
  #ifdef USE_KEYNAV_LIMIT
            ui_mouse_motion_keynav_init(&data->searchbox_keynav_state, event);
  #endif
 -          ui_searchbox_event(C, data->searchbox, but, event);
 +          ui_searchbox_event(C, data->searchbox, but, data->region, event);
            break;
          }
          if (event->type == WHEELDOWNMOUSE) {
  #ifdef USE_KEYNAV_LIMIT
            ui_mouse_motion_keynav_init(&data->searchbox_keynav_state, event);
  #endif
 -          ui_searchbox_event(C, data->searchbox, but, event);
 +          ui_searchbox_event(C, data->searchbox, but, data->region, event);
            break;
          }
          if (event->type == WHEELUPMOUSE) {
          }
          retval = WM_UI_HANDLER_BREAK;
          break;
 +      case EVT_ZKEY: {
 +        /* Ctrl-Z or Ctrl-Shift-Z: Undo/Redo (allowing for OS-Key on Apple). */
 +
 +        const bool is_redo = (event->shift != 0);
 +        if (
 +#if defined(__APPLE__)
 +            (event->oskey && !IS_EVENT_MOD(event, alt, ctrl)) ||
 +#endif
 +            (event->ctrl && !IS_EVENT_MOD(event, alt, oskey))) {
 +          int undo_pos;
 +          const char *undo_str = ui_textedit_undo(
 +              data->undo_stack_text, is_redo ? 1 : -1, &undo_pos);
 +          if (undo_str != NULL) {
 +            ui_textedit_string_set(but, data, undo_str);
 +
 +            /* Set the cursor & clear selection. */
 +            but->pos = undo_pos;
 +            but->selsta = but->pos;
 +            but->selend = but->pos;
 +            changed = true;
 +          }
 +          retval = WM_UI_HANDLER_BREAK;
 +          skip_undo_push = true;
 +        }
 +        break;
 +      }
      }
  
      if ((event->ascii || event->utf8_buf[0]) && (retval == WM_UI_HANDLER_CONTINUE)
  #endif
  
    if (changed) {
 +    /* The undo stack may be NULL if an event exits editing. */
 +    if ((skip_undo_push == false) && (data->undo_stack_text != NULL)) {
 +      ui_textedit_undo_push(data->undo_stack_text, data->str, but->pos);
 +    }
 +
      /* only do live update when but flag request it (UI_BUT_TEXTEDIT_UPDATE). */
      if (update && data->interactive) {
        ui_apply_but(C, block, but, data, true);
@@@ -4446,8 -4397,7 +4446,8 @@@ static int ui_do_but_TOG(bContext *C, u
          do_activate = (event->val == KM_RELEASE);
        }
        else {
 -        do_activate = (event->val == KM_PRESS);
 +        /* Also use double-clicks to prevent fast clicks to leak to other handlers (T76481). */
 +        do_activate = ELEM(event->val, KM_PRESS, KM_DBL_CLICK);
        }
      }
  
@@@ -8263,22 -8213,11 +8263,22 @@@ static uiBut *ui_context_rna_button_act
    return ui_context_button_active(CTX_wm_region(C), ui_context_rna_button_active_test);
  }
  
 -uiBut *UI_context_active_but_get(const struct bContext *C)
 +uiBut *UI_context_active_but_get(const bContext *C)
  {
    return ui_context_button_active(CTX_wm_region(C), NULL);
  }
  
 +/*
 + * Version of #UI_context_active_get() that uses the result of #CTX_wm_menu()
 + * if set. Does not traverse into parent menus, which may be wanted in some
 + * cases.
 + */
 +uiBut *UI_context_active_but_get_respect_menu(const bContext *C)
 +{
 +  ARegion *ar_menu = CTX_wm_menu(C);
 +  return ui_context_button_active(ar_menu ? ar_menu : CTX_wm_region(C), NULL);
 +}
 +
  uiBut *UI_region_active_but_get(ARegion *region)
  {
    return ui_context_button_active(region, NULL);
@@@ -8337,6 -8276,11 +8337,11 @@@ void UI_context_active_but_prop_handle(
    }
  }
  
+ void UI_context_active_but_clear(bContext *C, wmWindow *win, ARegion *region)
+ {
+   wm_event_handler_ui_cancel_ex(C, win, region, false);
+ }
  wmOperator *UI_context_active_operator_get(const struct bContext *C)
  {
    ARegion *region_ctx = CTX_wm_region(C);
@@@ -8868,14 -8812,14 +8873,14 @@@ static int ui_handle_button_event(bCont
      if (post_but) {
        button_activate_init(C, region, post_but, post_type);
      }
-     else {
+     else if (!((event->type == EVT_BUT_CANCEL) && (event->val == 1))) {
        /* XXX issue is because WM_event_add_mousemove(wm) is a bad hack and not reliable,
         * if that gets coded better this bypass can go away too.
         *
         * This is needed to make sure if a button was active,
         * it stays active while the mouse is over it.
         * This avoids adding mousemoves, see: [#33466] */
 -      if (ELEM(state_orig, BUTTON_STATE_INIT, BUTTON_STATE_HIGHLIGHT)) {
 +      if (ELEM(state_orig, BUTTON_STATE_INIT, BUTTON_STATE_HIGHLIGHT, BUTTON_STATE_WAIT_DRAG)) {
          if (ui_but_find_mouse_over(region, event) == but) {
            button_activate_init(C, region, but, BUTTON_ACTIVATE_OVER);
          }
@@@ -9400,11 -9344,6 +9405,11 @@@ static int ui_handle_menu_button(bConte
      if (event->val == KM_RELEASE) {
        /* pass, needed so we can exit active menu-items when click-dragging out of them */
      }
 +    else if (but->type == UI_BTYPE_SEARCH_MENU) {
 +      /* Pass, needed so search popup can have RMB context menu.
 +       * This may be useful for other interactions which happen in the search popup
 +       * without being directly over the search button. */
 +    }
      else if (!ui_block_is_menu(but->block) || ui_block_is_pie_menu(but->block)) {
        /* pass, skip for dialogs */
      }
@@@ -10838,6 -10777,9 +10843,6 @@@ static int ui_popup_handler(bContext *C
        if (temp.popup_func) {
          temp.popup_func(C, temp.popup_arg, temp.retvalue);
        }
 -      if (temp.optype) {
 -        WM_operator_name_call_ptr(C, temp.optype, temp.opcontext, NULL);
 -      }
      }
      else if (temp.cancel_func) {
        temp.cancel_func(C, temp.popup_arg);
index 530b6446a5040a5bef38cc3c05cc24f50a3d97b0,136c24f8056f37ab33a1f81993f7d250892c985f..8a9f9bc933427b05978842abf38e901468a6d47a
@@@ -640,11 -640,11 +640,11 @@@ static int wm_handler_ui_call(bContext 
    return WM_HANDLER_CONTINUE;
  }
  
- static void wm_handler_ui_cancel(bContext *C)
+ void wm_event_handler_ui_cancel_ex(bContext *C,
+                                    wmWindow *win,
+                                    ARegion *region,
+                                    bool reactivate_button)
  {
-   wmWindow *win = CTX_wm_window(C);
-   ARegion *region = CTX_wm_region(C);
    if (!region) {
      return;
    }
        wmEvent event;
        wm_event_init_from_window(win, &event);
        event.type = EVT_BUT_CANCEL;
+       event.val = reactivate_button ? 0 : 1;
        handler->handle_fn(C, &event, handler->user_data);
      }
    }
  }
  
+ static void wm_event_handler_ui_cancel(bContext *C)
+ {
+   wmWindow *win = CTX_wm_window(C);
+   ARegion *region = CTX_wm_region(C);
+   wm_event_handler_ui_cancel_ex(C, win, region, true);
+ }
  /** \} */
  
  /* -------------------------------------------------------------------- */
@@@ -1365,7 -1373,7 +1373,7 @@@ static int wm_operator_invoke(bContext 
         * while dragging the view or worse, that stay there permanently
         * after the modal operator has swallowed all events and passed
         * none to the UI handler */
-       wm_handler_ui_cancel(C);
+       wm_event_handler_ui_cancel(C);
      }
      else {
        WM_operator_free(op);
@@@ -3186,9 -3194,9 +3194,9 @@@ void wm_event_do_handlers(bContext *C
            }
  
            if (is_playing_sound == 0) {
 -            const float time = BKE_sound_sync_scene(scene_eval);
 +            const double time = BKE_sound_sync_scene(scene_eval);
              if (isfinite(time)) {
 -              int ncfra = time * (float)FPS + 0.5f;
 +              int ncfra = time * FPS + 0.5;
                if (ncfra != scene->r.cfra) {
                  scene->r.cfra = ncfra;
                  ED_update_for_newframe(CTX_data_main(C), depsgraph);