/* Get the touched action. * egde_offset is a percentage value for the position of the touch * inside the bar for regions which arnt WPS_TOUCHREGION_ACTION type. */ int skin_get_touchaction(struct wps_data *data, int* edge_offset, struct touchregion **retregion) { int returncode = ACTION_NONE; short x,y; short vx, vy; int type = action_get_touchscreen_press(&x, &y); struct skin_viewport *wvp; struct touchregion *r, *temp = NULL; char* skin_buffer = get_skin_buffer(data); bool repeated = (type == BUTTON_REPEAT); bool released = (type == BUTTON_REL); bool pressed = (type == BUTTON_TOUCHSCREEN); struct skin_token_list *regions = SKINOFFSETTOPTR(skin_buffer, data->touchregions); bool needs_repeat; while (regions) { struct wps_token *token = SKINOFFSETTOPTR(skin_buffer, regions->token); r = SKINOFFSETTOPTR(skin_buffer, token->value.data); wvp = SKINOFFSETTOPTR(skin_buffer, r->wvp); /* make sure this region's viewport is visible */ if (wvp->hidden_flags&VP_DRAW_HIDDEN) { regions = SKINOFFSETTOPTR(skin_buffer, regions->next); continue; } if (data->touchscreen_locked && (r->action != ACTION_TOUCH_SOFTLOCK && !r->allow_while_locked)) { regions = SKINOFFSETTOPTR(skin_buffer, regions->next); continue; } needs_repeat = r->press_length != PRESS; /* check if it's inside this viewport */ if (viewport_point_within_vp(&(wvp->vp), x, y)) { /* reposition the touch inside the viewport since touchregions * are relative to a preceding viewport */ vx = x - wvp->vp.x; vy = y - wvp->vp.y; /* now see if the point is inside this region */ if (vx >= r->x && vx < r->x+r->width && vy >= r->y && vy < r->y+r->height) { /* reposition the touch within the area */ vx -= r->x; vy -= r->y; switch(r->action) { case ACTION_TOUCH_SCROLLBAR: case ACTION_TOUCH_VOLUME: case ACTION_TOUCH_SETTING: if (edge_offset) { struct progressbar *bar = SKINOFFSETTOPTR(skin_buffer, r->bar); if(r->width > r->height) *edge_offset = vx*100/r->width; else *edge_offset = vy*100/r->height; if (r->reverse_bar || (bar && bar->invert_fill_direction)) *edge_offset = 100 - *edge_offset; } temp = r; returncode = r->action; r->last_press = current_tick; break; default: if (r->armed && ((repeated && needs_repeat) || (released && !needs_repeat))) { returncode = r->action; temp = r; } if (pressed) { r->armed = true; r->last_press = current_tick; } break; } } } regions = SKINOFFSETTOPTR(skin_buffer, regions->next); } /* On release, all regions are disarmed. */ if (released) skin_disarm_touchregions(data); if (retregion && temp) *retregion = temp; if (temp && temp->press_length == LONG_PRESS) temp->armed = false; if (returncode != ACTION_NONE) { if (global_settings.party_mode) { switch (returncode) { case ACTION_WPS_PLAY: case ACTION_WPS_SKIPPREV: case ACTION_WPS_SKIPNEXT: case ACTION_WPS_STOP: returncode = ACTION_NONE; break; default: break; } } switch (returncode) { case ACTION_TOUCH_SOFTLOCK: data->touchscreen_locked = !data->touchscreen_locked; returncode = ACTION_NONE; break; case ACTION_WPS_PLAY: if (!audio_status()) { if ( global_status.resume_index != -1 ) { if (playlist_resume() != -1) { playlist_start(global_status.resume_index, global_status.resume_offset); } } else { splash(HZ*2, ID2P(LANG_NOTHING_TO_RESUME)); } } else { wps_do_playpause(false); } returncode = ACTION_REDRAW; break; case ACTION_WPS_SKIPPREV: audio_prev(); returncode = ACTION_REDRAW; break; case ACTION_WPS_SKIPNEXT: audio_next(); returncode = ACTION_REDRAW; break; case ACTION_WPS_STOP: audio_stop(); returncode = ACTION_REDRAW; break; case ACTION_SETTINGS_INC: case ACTION_SETTINGS_DEC: { const struct settings_list *setting = temp->setting_data.setting; option_select_next_val(setting, returncode == ACTION_SETTINGS_DEC, true); returncode = ACTION_REDRAW; } break; case ACTION_SETTINGS_SET: { struct touchsetting *data = &temp->setting_data; const struct settings_list *s = data->setting; void (*f)(int) = NULL; switch (s->flags&F_T_MASK) { case F_T_CUSTOM: s->custom_setting ->load_from_cfg(s->setting, SKINOFFSETTOPTR(skin_buffer, data->value.text)); break; case F_T_INT: case F_T_UINT: *(int*)s->setting = data->value.number; if ((s->flags & F_T_SOUND) == F_T_SOUND) sound_set(s->sound_setting->setting, data->value.number); else if (s->flags&F_CHOICE_SETTING) f = s->choice_setting->option_callback; else if (s->flags&F_TABLE_SETTING) f = s->table_setting->option_callback; else f = s->int_setting->option_callback; if (f) f(data->value.number); break; case F_T_BOOL: *(bool*)s->setting = data->value.number ? true : false; if (s->bool_setting->option_callback) s->bool_setting ->option_callback(data->value.number ? true : false); break; } returncode = ACTION_REDRAW; } break; case ACTION_TOUCH_MUTE: { const int min_vol = sound_min(SOUND_VOLUME); if (global_settings.volume == min_vol) global_settings.volume = temp->value; else { temp->value = global_settings.volume; global_settings.volume = min_vol; } setvol(); returncode = ACTION_REDRAW; } break; case ACTION_TOUCH_SHUFFLE: /* toggle shuffle mode */ { global_settings.playlist_shuffle = !global_settings.playlist_shuffle; replaygain_update(); if (global_settings.playlist_shuffle) playlist_randomise(NULL, current_tick, true); else playlist_sort(NULL, true); returncode = ACTION_REDRAW; } break; case ACTION_TOUCH_REPMODE: /* cycle the repeat mode setting */ { const struct settings_list *rep_setting = find_setting(&global_settings.repeat_mode, NULL); option_select_next_val(rep_setting, false, true); audio_flush_and_reload_tracks(); returncode = ACTION_REDRAW; } break; case ACTION_TOUCH_SETTING: { struct progressbar *bar = SKINOFFSETTOPTR(skin_buffer, temp->bar); if (bar && edge_offset) { int val, count; get_setting_info_for_bar(bar->setting_id, &count, &val); val = *edge_offset * count / 100; update_setting_value_from_touch(bar->setting_id, val); } } break; } return returncode; } return ACTION_TOUCHSCREEN; }
/* Receive a command from the client and execute it. */ static void handle_command (const int client_id) { int cmd; int err = 0; struct client *cli = &clients[client_id]; if (!get_int(cli->socket, &cmd)) { logit ("Failed to get command from the client"); close (cli->socket); del_client (cli); return; } switch (cmd) { case CMD_QUIT: logit ("Exit request from the client"); close (cli->socket); del_client (cli); server_quit = 1; break; case CMD_LIST_CLEAR: logit ("Clearing the list"); audio_plist_clear (); break; case CMD_LIST_ADD: if (!req_list_add(cli)) err = 1; break; case CMD_PLAY: if (!req_play(cli)) err = 1; break; case CMD_DISCONNECT: logit ("Client disconnected"); close (cli->socket); del_client (cli); break; case CMD_PAUSE: audio_pause (); break; case CMD_UNPAUSE: audio_unpause (); break; case CMD_STOP: audio_stop (); break; case CMD_GET_CTIME: if (!send_data_int(cli, MAX(0, audio_get_time()))) err = 1; break; case CMD_SEEK: if (!req_seek(cli)) err = 1; break; case CMD_JUMP_TO: if (!req_jump_to(cli)) err = 1; break; case CMD_GET_SNAME: if (!send_sname(cli)) err = 1; break; case CMD_GET_STATE: if (!send_data_int(cli, audio_get_state())) err = 1; break; case CMD_GET_BITRATE: if (!send_data_int(cli, sound_info.bitrate)) err = 1; break; case CMD_GET_AVG_BITRATE: if (!send_data_int(cli, sound_info.avg_bitrate)) err = 1; break; case CMD_GET_RATE: if (!send_data_int(cli, sound_info.rate)) err = 1; break; case CMD_GET_CHANNELS: if (!send_data_int(cli, sound_info.channels)) err = 1; break; case CMD_NEXT: audio_next (); break; case CMD_PREV: audio_prev (); break; case CMD_PING: if (!send_int(cli->socket, EV_PONG)) err = 1; break; case CMD_GET_OPTION: if (!send_option(cli)) err = 1; break; case CMD_SET_OPTION: if (!get_set_option(cli)) err = 1; break; case CMD_GET_MIXER: if (!send_data_int(cli, audio_get_mixer())) err = 1; break; case CMD_SET_MIXER: if (!set_mixer(cli)) err = 1; break; case CMD_DELETE: if (!delete_item(cli)) err = 1; break; case CMD_SEND_PLIST_EVENTS: cli->wants_plist_events = 1; logit ("Request for events"); break; case CMD_GET_PLIST: if (!get_client_plist(cli)) err = 1; break; case CMD_SEND_PLIST: if (!req_send_plist(cli)) err = 1; break; case CMD_CAN_SEND_PLIST: cli->can_send_plist = 1; break; case CMD_CLI_PLIST_ADD: case CMD_CLI_PLIST_DEL: case CMD_CLI_PLIST_CLEAR: case CMD_CLI_PLIST_MOVE: if (!plist_sync_cmd(cli, cmd)) err = 1; break; case CMD_LOCK: if (!client_lock(cli)) err = 1; break; case CMD_UNLOCK: if (!client_unlock(cli)) err = 1; break; case CMD_GET_SERIAL: if (!send_serial(cli)) err = 1; break; case CMD_PLIST_GET_SERIAL: if (!req_plist_get_serial(cli)) err = 1; break; case CMD_PLIST_SET_SERIAL: if (!req_plist_set_serial(cli)) err = 1; break; case CMD_GET_TAGS: if (!req_get_tags(cli)) err = 1; break; case CMD_TOGGLE_MIXER_CHANNEL: req_toggle_mixer_channel (); break; case CMD_TOGGLE_SOFTMIXER: req_toggle_softmixer (); break; case CMD_GET_MIXER_CHANNEL_NAME: if (!req_get_mixer_channel_name(cli)) err = 1; break; case CMD_GET_FILE_TAGS: if (!get_file_tags(client_id)) err = 1; break; case CMD_ABORT_TAGS_REQUESTS: if (!abort_tags_requests(client_id)) err = 1; break; case CMD_LIST_MOVE: if (!req_list_move(cli)) err = 1; break; case CMD_TOGGLE_EQUALIZER: req_toggle_equalizer(); break; case CMD_EQUALIZER_REFRESH: req_equalizer_refresh(); break; case CMD_EQUALIZER_PREV: req_equalizer_prev(); break; case CMD_EQUALIZER_NEXT: req_equalizer_next(); break; case CMD_TOGGLE_MAKE_MONO: req_toggle_make_mono(); break; case CMD_QUEUE_ADD: if (!req_queue_add(cli)) err = 1; break; case CMD_QUEUE_DEL: if (!req_queue_del(cli)) err = 1; break; case CMD_QUEUE_CLEAR: logit ("Clearing the queue"); audio_queue_clear (); add_event_all (EV_QUEUE_CLEAR, NULL); break; case CMD_QUEUE_MOVE: if (!req_queue_move(cli)) err = 1; break; case CMD_GET_QUEUE: if (!req_send_queue(cli)) err = 1; break; default: logit ("Bad command (0x%x) from the client", cmd); err = 1; } if (err) { logit ("Closing client connection due to error"); close (cli->socket); del_client (cli); } }