/**************** * We have read in all header lines and are about to receive the body * part. The delimiter line has already been processed. * * FIXME: we's better return an error in case of memory failures. */ static int transition_to_body (rfc822parse_t msg) { rfc822parse_field_t ctx; int rc; rc = do_callback (msg, RFC822PARSE_T2BODY); if (!rc) { /* Store the boundary if we have multipart type. */ ctx = rfc822parse_parse_field (msg, "Content-Type", -1); if (ctx) { const char *s; s = rfc822parse_query_media_type (ctx, NULL); if (s && !strcmp (s,"multipart")) { s = rfc822parse_query_parameter (ctx, "boundary", 0); if (s) { assert (!msg->current_part->boundary); msg->current_part->boundary = malloc (strlen (s) + 1); if (msg->current_part->boundary) { part_t part; strcpy (msg->current_part->boundary, s); msg->boundary = msg->current_part->boundary; part = new_part (); if (!part) { int save_errno = errno; rfc822parse_release_field (ctx); errno = save_errno; return -1; } rc = do_callback (msg, RFC822PARSE_LEVEL_DOWN); assert (!msg->current_part->down); msg->current_part->down = part; msg->current_part = part; msg->in_preamble = 1; } } } rfc822parse_release_field (ctx); } } return rc; }
//回调函数,第三个参数为NULL,不使用 void GetRuleTask::done_get_new_rule(void *req , RET_TYPE type , void *data) { MsgHeader header; InReq *cb_req = NULL; //如果SCAgent执行失败,不再执行接下来的操纵,回调上层的回调函数, //当然还可以使用其它的设置,例如重试多次等 if(Task::parse_callback_ret(req , type) < 0) { goto ERR ; } cb_req = (InReq *)req; header = cb_req->m_msgHeader; //检查回复的报文的cmd字段是否符合定义,如果出错也不会执行接下来的操作 if(MU_RULER == m_type && MSG_RS_CS_UPDATE_MU_HASH_ACK != header.cmd) { LOG_ERROR("GetRuleTask::Undefined mu ack header cmd : " + int_to_str(header.cmd)); goto ERR ; } if(SU_RULER == m_type && MSG_RS_CS_UPDATE_SU_HASH_ACK != header.cmd) { LOG_ERROR("GetRuleTask::Undefined su ack header cmd : " + int_to_str(header.cmd)); goto ERR ; } //这里需要保证原子性! if(get_new_rule_ack(cb_req) < 0) { LOG_ERROR("GetRuleTask::Parse new rule from CS error !"); goto ERR ; } //每次更新报文之后都需要唤醒所有等待的客户端 if(m_is_wait_client) { wakeup_all_wait_request(); } //唤醒之后就可以执行回调了 do_callback(true); ERR : //这里可以使用其他的方式处理操作失败的情况,或者对不同的失败情况执行不同的操作 //这里仅仅是回调上层执行失败 if(m_is_wait_client) { wakeup_all_wait_request(); } do_callback(false); }
int orb_mapctrl::handle(int event) { switch (event) { case FL_MOVE: m_mousepos.set_x(Fl::event_x()-x()); m_mousepos.set_y(Fl::event_y()-y()); return 1; case FL_ENTER: fl_cursor(FL_CURSOR_HAND); return 1; case FL_LEAVE: fl_cursor(FL_CURSOR_DEFAULT); return 1; case FL_PUSH: if (Fl::event_button() == FL_RIGHT_MOUSE) do_callback(); return 1; case FL_RELEASE: return 1; case FL_DRAG: { if (!Fl::event_inside(this)) break; int dx = m_mousepos.get_x() - (Fl::event_x()-x()); int dy = m_mousepos.get_y() - (Fl::event_y()-y()); m_mousepos.set_x(Fl::event_x()-x()); m_mousepos.set_y(Fl::event_y()-y()); m_viewport->move(dx, dy); redraw(); return 1; } case FL_MOUSEWHEEL: if (!Fl::event_inside(this)) break; // Prevent integer underflow if ((Fl::event_dy() > 0) && (m_viewport->z() == 0)) return 1; // The image of the viewport might be smaller then our current // client area. We need to take this delta into account. int dpx = 0, dpy = 0; if (w() > (int)m_viewport->w()) dpx = (w() - (int)m_viewport->w())/2; if (h() > (int)m_viewport->h()) dpy = (h() - (int)m_viewport->h())/2; int px = Fl::event_x()- x() - dpx; int py = Fl::event_y()- y() - dpy; m_viewport->z(m_viewport->z()-Fl::event_dy(), px, py); redraw(); return 1; } return Fl_Widget::handle(event); }
int Fl_Envelope::handle(int event) { int ret=Fl_Group::handle(event); // search for deleted handles for(list<Fl_Handle*>::iterator i = m_HandleList.begin(); i!=m_HandleList.end(); ++i) { // if it's been modified, update the env via the callback if ((*i)->Changed()) do_callback(); if ((*i)->Deleted()) { remove(*i); m_HandleList.erase(i); break; // one at a time } } if (!ret) { int Mousebutton=Fl::event_button(); if (event==FL_PUSH && Mousebutton==2) { Fl_Handle * newhandle = new Fl_Handle(Fl::event_x()-5,Fl::event_y()-5,10,10,""); m_HandleList.push_back(newhandle); add(newhandle); } redraw(); } return ret; }
void EnvelopeFreeEdit::OSC_raw(const char *msg) { const char *args = rtosc_argument_string(msg); if(strstr(msg,"Penvpoints") && !strcmp(args, "i")) { Penvpoints = rtosc_argument(msg, 0).i; } else if(strstr(msg,"Penvdt") && !strcmp(args, "b")) { rtosc_blob_t b = rtosc_argument(msg, 0).b; assert(b.len == MAX_ENVELOPE_POINTS); memcpy(Penvdt, b.data, MAX_ENVELOPE_POINTS); } else if(strstr(msg,"Penvval") && !strcmp(args, "b")) { rtosc_blob_t b = rtosc_argument(msg, 0).b; assert(b.len == MAX_ENVELOPE_POINTS); memcpy(Penvval, b.data, MAX_ENVELOPE_POINTS); } else if(strstr(msg, "Penvval") && !strcmp(args, "c")) { const char *str = strstr(msg, "Penvval"); int id = atoi(str+7); assert(0 <= id && id < MAX_ENVELOPE_POINTS); Penvval[id] = rtosc_argument(msg, 0).i; } else if(strstr(msg, "Penvdt") && !strcmp(args, "c")) { const char *str = strstr(msg, "Penvdt"); int id = atoi(str+6); assert(0 <= id && id < MAX_ENVELOPE_POINTS); Penvdt[id] = rtosc_argument(msg, 0).i; } else if(strstr(msg,"Penvsustain") && !strcmp(args, "i")) { Penvsustain = rtosc_argument(msg, 0).i; } redraw(); do_callback(); }
void gdMidiOutputMidiCh::__cb_close() { ch->midiOut = enableOut->value(); ch->midiOutChan = chanListOut->value(); ch->midiOutL = enableLightning->value(); ch->guiChannel->update(); do_callback(); }
/**************** * Add header lines to the existing ones. * Such a line may include LFs which are used to split the line * int several fields. This must be a valid header line. */ int rfc822_add_header( RFC822 msg, const char *line ) { HDR_LINE hdr; const char *lf; size_t n; int do_cb; /* send the notification only if we have not processed all header lines */ do_cb = !msg->in_body && strlen(line) >= 9 && !memicmp(line, "Received:", 9); do { lf = strchr( line, '\n' ); n = lf? ( lf - line ) : strlen( line ); hdr = malloc( sizeof( *hdr ) + n ); if( !hdr ) return RFC822ERR_NOMEM; hdr->next = NULL; hdr->cont = (*line == ' ' || *line == '\t'); memcpy(hdr->line, line, n ); hdr->line[n] = 0; *msg->hdr_lines_head = hdr; msg->hdr_lines_head = &hdr->next; } while( lf && *(line=lf+1) ); if( do_cb ) do_callback( msg, RFC822EVT_RCVD_SEEN ); return 0; }
/**************** * Note: For program supplied (and therefore syntactically correct) * header lines, rfc822_add_header() may be used. */ int insert_header( RFC822 msg, char *line, size_t length ) { HDR_LINE hdr; if( !length ) { msg->in_body = 1; return transition_to_body(msg); } trim_trailing_spaces(line); /* Hmmm: should we check for invalid header data here? */ hdr = malloc( sizeof( *hdr ) + strlen(line) ); if( !hdr ) return RFC822ERR_NOMEM; hdr->next = NULL; hdr->cont = (*line == ' ' || *line == '\t'); strcpy(hdr->line, line ); *msg->hdr_lines_head = hdr; msg->hdr_lines_head = &hdr->next; /* lets help the caller to prevent mail loops * It is okay to use length here, also this value * not correct due to the space trimming */ if( length >= 9 && !memicmp(line, "Received:", 9) ) do_callback( msg, RFC822EVT_RCVD_SEEN ); return 0; }
void rfc822_close( RFC822 msg ) { do_callback( msg, RFC822EVT_CLOSE ); release_handle_data( msg ); free(msg); }
void rfc822_cancel( RFC822 msg ) { do_callback( msg, RFC822EVT_CANCEL ); release_handle_data( msg ); free(msg); }
void gdBeatsInput::__cb_update_batt() { if (!strcmp(beats->value(), "") || !strcmp(bars->value(), "")) return; glue_setBeats(atoi(beats->value()), atoi(bars->value()), resizeRec->value()); do_callback(); }
/** * @brief Updates all timers currently running for this script. */ void LuaContext::update_timers() { // Update all timers. std::map<Timer*, LuaTimerData>::iterator it; for (it = timers.begin(); it != timers.end(); ++it) { Timer* timer = it->first; timer->update(); if (timer->is_finished()) { do_callback(it->second.callback_ref); it->second.callback_ref = LUA_REFNIL; timers_to_remove.push_back(timer); } } // Destroy the ones that should be removed. std::list<Timer*>::iterator it2; for (it2 = timers_to_remove.begin(); it2 != timers_to_remove.end(); ++it2) { Timer* timer = *it2; if (timers.find(timer) != timers.end()) { if (!timer->is_finished()) { cancel_callback(timers[timer].callback_ref); } timers.erase(timer); timer->decrement_refcount(); if (timer->get_refcount() == 0) { delete timer; } } } timers_to_remove.clear(); }
/* * FIXME: icon will loose focus if is selected then press OK, which will take focus from it. * In this case, nothing will be returned; double-click works as expected. */ int IconBox::handle(int event) { switch(event) { case FL_FOCUS: corig = color(); color(selection_color()); redraw(); sel = true; return 1; case FL_UNFOCUS: color(corig); redraw(); sel = false; return 1; case FL_PUSH: take_focus(); // double-click if(Fl::event_clicks()) do_callback(); return 1; case FL_RELEASE: return 1; default: return Fl_Button::handle(event); } return 1; }
// When user picks a menu item, call this. It will do the callback. // Unfortunatly this also casts away const for the checkboxes, but this // was necessary so non-checkbox menus can really be declared const... const MenuItem* MenuBase::picked(const MenuItem* v) { if (v) { if (v->radio()) { if (!v->value()) { // they are turning on a radio item set_changed(); ((MenuItem*)v)->setonly(); } redraw(); } else if (v->flags & FL_MENU_TOGGLE) { set_changed(); ((MenuItem*)v)->flags ^= FL_MENU_VALUE; redraw(); } else if (v != value_) { // normal item set_changed(); } value_ = v; if (when()&(FL_WHEN_CHANGED|FL_WHEN_RELEASE)) { if (changed() || when()&FL_WHEN_NOT_CHANGED) { if (value_ && value_->callback_) value_->do_callback((Fl_Widget*)this); else do_callback(); } } } return v; }
int IndicatorWindow::handle(int iEvent) { switch (iEvent) { case FL_PUSH: switch (Fl::event_button()) { case 1: // left button { // find the indicator and move the floating indicator there int x = Fl::event_x(); float fIndicator = findIndicator(x, 5); if (fIndicator != ks_fIndicatorNotFound) { floatingIndicator(fIndicator); redraw(); } } break; } return 1; case FL_RELEASE: switch (Fl::event_button()) { case 1: // left button // do the callback function so that the parent can update other // widgets accordingly do_callback(); break; } return 1; default: break; } return Fl_Double_Window::handle(iEvent); }
void Flu_Combo_Box :: selected( const char *v ) { if( v ) input.value( v ); _popped = false; do_callback(); }
/* Create a new parsing context for an entire rfc822 message and return it. CB and CB_VALUE may be given to callback for certain events. NULL is returned on error with errno set appropriately. */ rfc822parse_t rfc822parse_open (rfc822parse_cb_t cb, void *cb_value) { rfc822parse_t msg = calloc (1, sizeof *msg); if (msg) { msg->parts = msg->current_part = new_part (); if (!msg->parts) { free (msg); msg = NULL; } else { msg->callback = cb; msg->callback_value = cb_value; if (do_callback (msg, RFC822PARSE_OPEN)) { release_handle_data (msg); free (msg); msg = NULL; } } } return msg; }
void gdBrowser::__cb_load_sample() { if (browser->text(browser->value()) == NULL) return; int res = glue_loadChannel((SampleChannel*) ch, browser->get_selected_item(), browser->path_obj->value()); if (res == SAMPLE_LOADED_OK) { do_callback(); mainWin->delSubWindow(WID_SAMPLE_EDITOR); // if editor is open } else if (res == SAMPLE_NOT_VALID) gdAlert("This is not a valid WAVE file."); else if (res == SAMPLE_MULTICHANNEL) gdAlert("Multichannel samples not supported."); else if (res == SAMPLE_WRONG_BIT) gdAlert("This sample has an\nunsupported bit-depth (> 32 bit)."); else if (res == SAMPLE_WRONG_ENDIAN) gdAlert("This sample has a wrong\nbyte order (not little-endian)."); else if (res == SAMPLE_WRONG_FORMAT) gdAlert("This sample is encoded in\nan unsupported audio format."); else if (res == SAMPLE_READ_ERROR) gdAlert("Unable to read this sample."); else if (res == SAMPLE_PATH_TOO_LONG) gdAlert("File path too long."); else gdAlert("Unknown error."); }
void gdBrowser::__cb_save_project() { if (strcmp(name->value(), "") == 0) { /// FIXME glue business gdAlert("Please choose a project name."); return; } /* check if name->value() contains ".gprj" */ char ext[6] = ".gprj"; if (strstr(name->value(), ".gprj") != NULL) ext[0] = '\0'; char fullpath[PATH_MAX]; #if defined(_WIN32) sprintf(fullpath, "%s\\%s%s", where->value(), name->value(), ext); #else sprintf(fullpath, "%s/%s%s", where->value(), name->value(), ext); #endif if (gIsProject(fullpath) && !gdConfirmWin("Warning", "Project exists: overwrite?")) return; if (glue_saveProject(fullpath, name->value())) do_callback(); else gdAlert("Unable to save the project!"); }
void Flu_Collapsable_Group :: open( bool o ) { _open = o; do_callback(); if( !_changing ) { _oldResizable = group.resizable(); group.resizable( NULL ); } if( _open ) { group.show(); _newHeight = _originalHeight; } else { _newHeight = button.h()+5; if( !_changing ) _originalHeight = h(); } _currentHeight = float(h()); if( !_changing ) { _timeout = 1.0f / _fps; _deltaHeight = ( float(_newHeight) - _currentHeight ) / ( _collapseTime * _fps ); _changing = true; Fl::add_timeout( _timeout, _updateCB, this ); } }
void Fl_MIDIKeyboard::release_key(uchar k) { if (pressed_keys[k]) { NoteOff(k); pressed_keys[k] = false; _npressed--; if (_npressed) { if (k == _maxpressed) { do k--; while (!pressed_keys[k]); _maxpressed = k; } else if (k == _minpressed) { do k++; while (!pressed_keys[k]); _minpressed = k; } } redraw(); if (when() & MKB_WHEN_RELEASE) { _callback_status = MKB_RELEASE | k; do_callback(); } //cout << "Released " << (char)k << " npressed = " << (int)_npressed << endl; } }
static void php_sqlite3_func_step_callback(sqlite3_context *context, int argc, sqlite3_value **argv) { struct pdo_sqlite_func *func = (struct pdo_sqlite_func*)sqlite3_user_data(context); do_callback(&func->astep, &func->step, argc, argv, context, 1); }
int orb_mapctrl::zoom_set(unsigned int z) { m_viewport->z(z, m_viewport->w()/2, m_viewport->h()/2); redraw(); do_callback(); return 0; }
/// mouse push void view::mouse_push(unsigned button) { // TODO: Check if selected mesh is visible, if it is not - return //if (!m_world->GetBaseMeshs().) { // return; //} return; if ((interaction_mode==MARK) && (button == fltk::LeftButton)) { if (basemesh_drawable->selected_edge) { basemesh_drawable->selected_edge->marked = !basemesh_drawable->selected_edge->marked; do_callback(); } if (basemesh_drawable->selected_vertex) { basemesh_drawable->selected_vertex->marked = !basemesh_drawable->selected_vertex->marked; do_callback(); } } if ((interaction_mode == TRANSLATE) && (button == fltk::RightButton) && (basemesh_drawable->selected_vertex)) { if (vertex_drag_mode == YZ) { vertex_drag_mode = X; } else { ((int&)vertex_drag_mode)++; } choice_2->value(vertex_drag_mode-1); basemesh_drawable->vertex_drag_mode = vertex_drag_mode; } if ((interaction_mode == SPLIT) && (button == fltk::LeftButton) && (basemesh_drawable->selected_edge)) { basemesh_drawable->mesh->split_edge(basemesh_drawable->selected_edge); do_callback(); } if ((interaction_mode == INSERT) && (button == fltk::LeftButton) && (basemesh_drawable->selected_vertex)) { if (!basemesh_drawable->marked_vertex) { basemesh_drawable->marked_vertex = basemesh_drawable->selected_vertex; } else { if (basemesh_drawable->selected_vertex == basemesh_drawable->marked_vertex) { basemesh_drawable->marked_vertex = NULL; } else { if (basemesh_drawable->mesh->insert_edge(basemesh_drawable->marked_vertex,basemesh_drawable->selected_vertex)) { basemesh_drawable->marked_vertex = NULL; do_callback(); } } } } }
int orb_mapctrl::refresh() { // Make sure the current zoomlevel is valid m_viewport->z(m_viewport->z(), m_viewport->w()/2, m_viewport->h()/2); do_callback(); redraw(); return 0; }
int addr_do(const struct in6_addr *addr, int plen, int ifindex, void *arg, int (*do_callback)(struct ifaddrmsg *ifa, struct rtattr *rta_tb[], void *arg)) { uint8_t sbuf[256]; uint8_t rbuf[256]; struct nlmsghdr *sn, *rn; struct ifaddrmsg *ifa; int err; struct rtattr *rta_tb[IFA_MAX+1]; memset(sbuf, 0, sizeof(sbuf)); sn = (struct nlmsghdr *)sbuf; sn->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg)); sn->nlmsg_flags = NLM_F_REQUEST; sn->nlmsg_type = RTM_GETADDR; ifa = NLMSG_DATA(sn); ifa->ifa_family = AF_INET6; ifa->ifa_prefixlen = plen; ifa->ifa_scope = RT_SCOPE_UNIVERSE; ifa->ifa_index = ifindex; addattr_l(sn, sizeof(sbuf), IFA_LOCAL, addr, sizeof(*addr)); memset(rbuf, 0, sizeof(rbuf)); rn = (struct nlmsghdr *)rbuf; err = rtnl_route_do(sn, rn); if (err < 0) { rn = sn; ifa = NLMSG_DATA(rn); } else { ifa = NLMSG_DATA(rn); if (rn->nlmsg_type != RTM_NEWADDR || rn->nlmsg_len < NLMSG_LENGTH(sizeof(*ifa)) || ifa->ifa_family != AF_INET6) { return -EINVAL; } } memset(rta_tb, 0, sizeof(rta_tb)); parse_rtattr(rta_tb, IFA_MAX, IFA_RTA(ifa), rn->nlmsg_len - NLMSG_LENGTH(sizeof(*ifa))); if (!rta_tb[IFA_ADDRESS]) rta_tb[IFA_ADDRESS] = rta_tb[IFA_LOCAL]; if (!rta_tb[IFA_ADDRESS] || !IN6_ARE_ADDR_EQUAL(RTA_DATA(rta_tb[IFA_ADDRESS]), addr)) { return -EINVAL; } if (do_callback) err = do_callback(ifa, rta_tb, arg); return err; }
/// mouse button pressed void view::mouse_move_button_pressed(unsigned button, int dx, int dy) { float mouse_sensitivity = 0.02f; if (/*((interaction_mode == MARK) && (!basemesh_drawable->selected_vertex) && (!basemesh_drawable->selected_edge))|| ((!basemesh_drawable->selected_vertex) && (interaction_mode == TRANSLATE))|| ((interaction_mode == SPLIT) && (!basemesh_drawable->selected_edge))|| ((interaction_mode == INSERT) && (!basemesh_drawable->selected_vertex))||*/ (interaction_mode == VIEWPOINT)) { vec_mouse.x() = -(float)dx; vec_mouse.y() = (float)dy; vec_mouse.z() = 0; switch (button) { case fltk::LeftButton: cam_azimut += mouse_sensitivity*float(dx); cam_polar += mouse_sensitivity*float(dy); break; case fltk::RightButton: cam_distance = max(-20000.0, min(20000.0, static_cast<double>(cam_distance + mouse_sensitivity*(float(dx) + float(dy)) + mouse_sensitivity*(float(dx) + float(dy)) * (1.0f / 5000.0f) * pow(cam_distance,2.0f)))); break; case fltk::MiddleButton: cam_target += (0.2f * mouse_sensitivity * (invert(m)*vec_mouse)); break; default: break; } } // TODO: Check if selected mesh is visible, if it is not - return //if (!m_world->GetBaseMeshs().) { // return; //} return; if ((interaction_mode == TRANSLATE) && (basemesh_drawable->selected_vertex) && (button == fltk::LeftButton)) { cgv::math::linalg::fix_col_vec<float,4> e1,e2; point3f e11,e22; e1.set(1.0f,0.0f,0.0f,1.0f); e2.set(0.0f,1.0f,0.0f,1.0f); cgv::math::linalg::fix_sqr_mat<float,4> mt = transpose(m); e1 = mt*e1; e2 = mt*e2; e11.set(e1.x()/e1.w(),e1.y()/e1.w(),e1.z()/e1.w()); e22.set(e2.x()/e2.w(),e2.y()/e2.w(),e2.z()/e2.w()); //todo:put pixel characteristics point3f delta = ((float)dx*e11) + ((float)-dy*e22); if ((vertex_drag_mode & X) == 0) { delta.x() = 0; } if ((vertex_drag_mode & Y) == 0) { delta.y() = 0; } if ((vertex_drag_mode & Z) == 0) { delta.z() = 0; } basemesh_drawable->selected_vertex->position += (0.5f * mouse_sensitivity * basemesh_drawable->mesh->avg_edge_length) * delta; do_callback(); } }
void rfc822parse_close (rfc822parse_t msg) { if (msg) { do_callback (msg, RFC822PARSE_CLOSE); release_handle_data (msg); free (msg); } }
void rfc822parse_cancel (rfc822parse_t msg) { if (msg) { do_callback (msg, RFC822PARSE_CANCEL); release_handle_data (msg); free (msg); } }
// Update an 'int' value, direction = 1 for increment, -1 for decrement static void update_int_value(const CMenuItem *mi, int direction) { // do update *(mi->value) += int_incr * direction; // Limit new value to defined bounds if ( mi->type & MENUITEM_F_UNSIGNED) { if (*(mi->value) < 0) *(mi->value) = 0; if ( mi->type & MENUITEM_F_MIN) { if (*(mi->value) < MENU_MIN_UNSIGNED(mi->arg)) *(mi->value) = MENU_MIN_UNSIGNED(mi->arg); } } else { if (*(mi->value) < -9999) *(mi->value) = -9999; if ( mi->type & MENUITEM_F_MIN) { if (*(mi->value) < MENU_MIN_SIGNED(mi->arg)) *(mi->value) = MENU_MIN_SIGNED(mi->arg); } } if (*(mi->value) > 99999) *(mi->value) = 99999; if ( mi->type & MENUITEM_F_UNSIGNED) { if ( mi->type & MENUITEM_F_MAX) { if (*(mi->value) > MENU_MAX_UNSIGNED(mi->arg)) *(mi->value) = MENU_MAX_UNSIGNED(mi->arg); } } else { if ( mi->type & MENUITEM_F_MAX) { if (*(mi->value) > MENU_MAX_SIGNED(mi->arg)) *(mi->value) = MENU_MAX_SIGNED(mi->arg); } } // execute custom callback and on_change functions do_callback(mi); // force menu redraw gui_menu_redraw=1; }