コード例 #1
0
void playmp_controller::process_network_data(bool chat_only)
{
	if(end_turn_ == END_TURN_SYNCED || is_regular_game_end() || player_type_changed_) {
		return;
	}
	turn_info::PROCESS_DATA_RESULT res = turn_info::PROCESS_CONTINUE;
	config cfg;
	if(!resources::recorder->at_end()) {
		res = turn_info::replay_to_process_data_result(do_replay());
	}
	else if(network_reader_.read(cfg)) {
		res = turn_data_.process_network_data(cfg, chat_only);
	}

	if (res == turn_info::PROCESS_CANNOT_HANDLE) {
		network_reader_.push_front(std::move(cfg));
	}
	else if (res == turn_info::PROCESS_RESTART_TURN) {
		player_type_changed_ = true;
	}
	else if (res == turn_info::PROCESS_END_TURN) {
		end_turn_ = END_TURN_SYNCED;
	}
	else if (res == turn_info::PROCESS_END_LEVEL) {
	}
	else if (res == turn_info::PROCESS_END_LINGER) {
		replay::process_error("Received unexpected next_scenario during the game");
	}
}
コード例 #2
0
static int start_file(char *name)
{
    char buf[MAXFILENAME+20];
    int fd;

    if (play_f!=-1)
    {
        replay_abort();
        close(play_f);
        play_f=-1;
        CancelWaitableTimer(timer);
        replay_pause();
        set_buttons(0);
    }
    fd=open_stream(-1, name, SM_READ, 0);
    if (fd==-1)
        return 0;
    play_f=fd;
    play_format=ttyrec_r_find_format(0, name, "baudrate");
    play_filename=name;
    replay_start();
    snprintf(buf, sizeof(buf), "Termplay: %s (%s)", filename, play_format);
    SetWindowText(wndMain, buf);
    set_toolbar_state(1);
    play_state=2;
    do_replay();
    return 1;
}
コード例 #3
0
possible_end_play_signal playmp_controller::play_network_turn(){
	LOG_NG << "is networked...\n";

	end_turn_enable(false);
	turn_data_.send_data();

	for(;;) {

		if (!network_processing_stopped_){
			config cfg;
			if(network_reader_.read(cfg)) {
				if (replay_last_turn_ <= turn()){
					if (skip_replay_) {
						skip_replay_ = false;
					}
				}
				turn_info::PROCESS_DATA_RESULT result;
				HANDLE_END_PLAY_SIGNAL ( result = turn_data_.process_network_data(cfg, skip_replay_) );
				if(player_type_changed_ == true)
				{
					//we received a player change/quit during waiting in get_user_choice/synced_context::pull_remote_user_input
					return boost::none;
				}
				if (result == turn_info::PROCESS_RESTART_TURN || result == turn_info::PROCESS_RESTART_TURN_TEMPORARY_LOCAL) {
					player_type_changed_ = true;
					return boost::none;
				} else if (result == turn_info::PROCESS_END_TURN) {
					break;
				}
			}
			/*
				we might have data left in replay that we recieved during prestart events. (or maybe other events.)
			*/
			else if(!recorder.at_end())
			{
				bool was_skipping = recorder.is_skipping();
				recorder.set_skip(skip_replay_);
				if(do_replay() == REPLAY_FOUND_END_TURN)
				{
					break;
				}
				recorder.set_skip(was_skipping);
			}
		}

		HANDLE_END_PLAY_SIGNAL( play_slice() );
		HANDLE_END_PLAY_SIGNAL( check_end_level() );

		if (!network_processing_stopped_){
			turn_data_.send_data();
		}

		gui_->draw();
	}

	LOG_NG << "finished networked...\n";
	return boost::none;
}
コード例 #4
0
ファイル: playturn.cpp プロジェクト: N4tr0n/wesnoth
turn_info::PROCESS_DATA_RESULT turn_info::handle_turn(const config& t)
{
	//t can contain a [command] or a [upload_log]
	assert(t.all_children_count() == 1);
	/** @todo FIXME: Check what commands we execute when it's our turn! */

	//note, that this function might call itself recursively: do_replay -> ... -> get_user_choice -> ... -> playmp_controller::pull_remote_choice -> sync_network -> handle_turn
	resources::recorder->add_config(t, replay::MARK_AS_SENT);
	PROCESS_DATA_RESULT retv = replay_to_process_data_result(do_replay());
	return retv;
}
コード例 #5
0
ファイル: replay_controller.cpp プロジェクト: AI0867/wesnoth
//make only one side move
void replay_controller::play_side(const unsigned int /*team_index*/, bool){

	DBG_REPLAY << "Status turn number: " << turn() << "\n";
	DBG_REPLAY << "Replay_Controller turn number: " << current_turn_ << "\n";
	DBG_REPLAY << "Player number: " << player_number_ << "\n";

	try{
		// If a side is empty skip over it.
		bool has_end_turn = true;
		if (!current_team().is_empty()) {
			statistics::reset_turn_stats(current_team().save_id());

			play_controller::init_side(player_number_ - 1, true);

			DBG_REPLAY << "doing replay " << player_number_ << "\n";
			// if have reached the end we don't want to execute finish_side_turn and finish_turn
			// becasue we might not have enough data to execute them (like advancements during turn_end for example)
			// !has_end_turn == we reached the end of teh replay without finding and end turn tag.
			has_end_turn = do_replay(player_number_);
			if(!has_end_turn)
			{
				return;
			}
			finish_side_turn();
		}

		player_number_++;

		if (static_cast<size_t>(player_number_) > teams_.size()) {
			//during the orginal game player_number_ would also be teams_.size(),
			player_number_ = teams_.size();
			finish_turn();
			tod_manager_.next_turn();
			it_is_a_new_turn_ = true;
			player_number_ = 1;
			current_turn_++;
			gui_->new_turn();
		}

		// This is necessary for replays in order to show possible movements.
		BOOST_FOREACH(unit &u, units_) {
			if (u.side() == player_number_) {
				u.new_turn();
			}
		}

		update_teams();
		update_gui();
	}
	catch(end_level_exception& e){
		//VICTORY/DEFEAT end_level_exception shall not return to title screen
		if (e.result != VICTORY && e.result != DEFEAT) throw;
	}
}
コード例 #6
0
static void replay_speed(int x)
{
    if (play_state==-1)
    {
        speed=x;
        return;
    }
    replay_pause();
    speed=x;
    replay_resume();
    do_replay();
}
コード例 #7
0
void replay_controller::play_side(const unsigned int /*team_index*/, bool){
	if (recorder.at_end()){
		return;
	}

	DBG_REPLAY << "Status turn number: " << turn() << "\n";
	DBG_REPLAY << "Replay_Controller turn number: " << current_turn_ << "\n";
	DBG_REPLAY << "Player number: " << player_number_ << "\n";

	try{
		// If a side is empty skip over it.
		if (!current_team().is_empty()) {
			statistics::reset_turn_stats(current_team().save_id());

			play_controller::init_side(player_number_ - 1, true);

			DBG_REPLAY << "doing replay " << player_number_ << "\n";
			do_replay(player_number_);

			finish_side_turn();

			// This is necessary for replays in order to show possible movements.
			for (unit_map::iterator uit = units_.begin(); uit != units_.end(); ++uit) {
				if (uit->second.side() != player_number_) {
					uit->second.new_turn();
				}
			}
		}

		player_number_++;

		if (static_cast<size_t>(player_number_) > teams_.size()) {
			next_turn();
			finish_turn();
			player_number_ = 1;
			current_turn_++;
		}

		update_teams();
		update_gui();
	}
	catch(end_level_exception& e){
		//VICTORY/DEFEAT end_level_exception shall not return to title screen
		if ((e.result != VICTORY) && (e.result != DEFEAT)) { throw e; }
	}
}
コード例 #8
0
static void gui_drawingarea_cb_key (I, GuiDrawingAreaKeyEvent event) {
	iam (RunnerMFC);
	if (my graphics == NULL) return;   // Could be the case in the very beginning.
	ExperimentMFC experiment = (ExperimentMFC) my data;
	if (my data == NULL) return;
	double reactionTime = Melder_clock () - experiment -> startingTime;
	if (! experiment -> blankWhilePlaying)
		reactionTime -= experiment -> stimulusInitialSilenceDuration;
	if (experiment -> trial == 0) {
	} else if (experiment -> pausing) {
	} else if (experiment -> trial <= experiment -> numberOfTrials) {
		long iresponse;
		if (experiment -> ok_key != NULL && experiment -> ok_key [0] == event -> key &&
			experiment -> responses [experiment -> trial] != 0 &&
			(experiment -> numberOfGoodnessCategories == 0 || experiment -> goodnesses [experiment -> trial] != 0))
		{
			do_ok (me);
		} else if (experiment -> replay_key != NULL && experiment -> replay_key [0] == event -> key &&
			my numberOfReplays < experiment -> maximumNumberOfReplays)
		{
			do_replay (me);
		} else if (experiment -> oops_key != NULL && experiment -> oops_key [0] == event -> key) {
			if (experiment -> trial > 1) {
				do_oops (me);
			}
		} else if (experiment -> responses [experiment -> trial] == 0) {
			for (iresponse = 1; iresponse <= experiment -> numberOfDifferentResponses; iresponse ++) {
				ResponseMFC response = & experiment -> response [iresponse];
				if (response -> key != NULL && response -> key [0] == event -> key) {
					experiment -> responses [experiment -> trial] = iresponse;
					experiment -> reactionTimes [experiment -> trial] = reactionTime;
					if (experiment -> responsesAreSounds) {
						ExperimentMFC_playResponse (experiment, iresponse);
					}
					if (experiment -> ok_right <= experiment -> ok_left && experiment -> numberOfGoodnessCategories == 0) {
						do_ok (me);
					} else {
						my broadcastDataChanged ();
						Graphics_updateWs (my graphics);
					}
				}
			}
		}
	}
}
コード例 #9
0
ファイル: playturn.cpp プロジェクト: N4tr0n/wesnoth
turn_info::PROCESS_DATA_RESULT turn_info::sync_network()
{
	//there should be nothing left on the replay and we should get turn_info::PROCESS_CONTINUE back.
	turn_info::PROCESS_DATA_RESULT retv = replay_to_process_data_result(do_replay());
	if(resources::controller->is_networked_mp()) {

		//receive data first, and then send data. When we sent the end of
		//the AI's turn, we don't want there to be any chance where we
		//could get data back pertaining to the next turn.
		config cfg;
		while( (retv == turn_info::PROCESS_CONTINUE) &&  network_reader_.read(cfg)) {
			retv = process_network_data(cfg);
			cfg.clear();
		}
		send_data();
	}
	return retv;
}
コード例 #10
0
static void adjust_pos(int d)
{
    int oldstate=play_state;

    if (play_state==-1)
        return;
    replay_pause();
    tr.tv_sec+=d;
    if (tr.tv_sec<0)
        tr.tv_sec=tr.tv_usec=0;
    if (tcmp(tr, tmax)==1)
        tr=tmax;
    replay_seek();
    play_state=oldstate;
    redraw_term();
    set_prog();
    do_replay();
}
コード例 #11
0
static void prog_scrolled(void)
{
    uint64_t v;
    int oldstate=play_state;
    int pos=SendMessage(wndProg, TBM_GETPOS, 0, 0);

    if (pos<0)
        pos=0;
    replay_pause();

    v=pos;
    v*=progdiv;
    tr.tv_sec=v/1000000;
    tr.tv_usec=v%1000000;
    replay_seek();
    play_state=oldstate;
    redraw_term();
    do_replay();
}
コード例 #12
0
void turn_info::handle_turn(
	bool& turn_end,
	const config& t,
	const bool skip_replay,
	std::deque<config>& backlog)
{
	if(turn_end == false) {
		/** @todo FIXME: Check what commands we execute when it's our turn! */
		replay_.append(t);
		replay_.set_skip(skip_replay);

		turn_end = do_replay(team_num_, &replay_);
		recorder.add_config(t, replay::MARK_AS_SENT);
	} else {

		//this turn has finished, so push the remaining moves
		//into the backlog
		backlog.push_back(config());
		backlog.back().add_child("turn", t);
	}
}
コード例 #13
0
//make only one side move
void replay_controller::play_side(const unsigned int /*team_index*/, bool){

	DBG_REPLAY << "Status turn number: " << turn() << "\n";
	DBG_REPLAY << "Replay_Controller turn number: " << current_turn_ << "\n";
	DBG_REPLAY << "Player number: " << player_number_ << "\n";

	try{
		// If a side is empty skip over it.
		if (!current_team().is_empty()) {
			statistics::reset_turn_stats(current_team().save_id());

			play_controller::init_side(player_number_ - 1, true);

			DBG_REPLAY << "doing replay " << player_number_ << "\n";
			do_replay(player_number_);

			finish_side_turn();

			// This is necessary for replays in order to show possible movements.
			foreach (unit &u, units_) {
				if (u.side() != player_number_) {
					u.new_turn();
				}
			}
		}

		player_number_++;

		if (static_cast<size_t>(player_number_) > teams_.size()) {
			finish_turn();
			tod_manager_.next_turn();
			it_is_a_new_turn_ = true;
			player_number_ = 1;
			current_turn_++;
			gui_->new_turn();
		}

		update_teams();
		update_gui();
	}
コード例 #14
0
static void gui_drawingarea_cb_click (I, GuiDrawingAreaClickEvent event) {
	iam (RunnerMFC);
	if (my graphics == NULL) return;   // Could be the case in the very beginning.
	ExperimentMFC experiment = (ExperimentMFC) my data;
	if (my data == NULL) return;
	double reactionTime = Melder_clock () - experiment -> startingTime;
	if (! experiment -> blankWhilePlaying)
		reactionTime -= experiment -> stimulusInitialSilenceDuration;
	double x, y;
	Graphics_DCtoWC (my graphics, event -> x, event -> y, & x, & y);
	if (experiment -> trial == 0) {   // the first click of the experiment
		experiment -> trial ++;
		my broadcastDataChanged ();
		if (experiment -> blankWhilePlaying) {
			Graphics_setGrey (my graphics, 0.8);
			Graphics_fillRectangle (my graphics, 0, 1, 0, 1);
			Graphics_setGrey (my graphics, 0.0);
			Graphics_flushWs (my graphics);
		}
		Graphics_updateWs (my graphics);
		if (experiment -> stimuliAreSounds) {
			if (experiment -> numberOfTrials < 1) {
				Melder_flushError ("There are zero trials in this experiment.");
				forget (me);
				return;
			}
			autoMelderAudioSaveMaximumAsynchronicity saveMaximumAsynchronicity;
			if (experiment -> blankWhilePlaying)
				MelderAudio_setOutputMaximumAsynchronicity (kMelder_asynchronicityLevel_SYNCHRONOUS);
			ExperimentMFC_playStimulus (experiment, experiment -> stimuli [1]);   // works only if there is at least one trial
		}
	} else if (experiment -> pausing) {   // a click to leave the break
		if (x > experiment -> oops_left && x < experiment -> oops_right &&
			y > experiment -> oops_bottom && y < experiment -> oops_top && experiment -> trial > 1)
		{
			do_oops (me);
		} else {
			experiment -> pausing = FALSE;
			experiment -> trial ++;
			my broadcastDataChanged ();
			if (experiment -> blankWhilePlaying) {
				Graphics_setGrey (my graphics, 0.8);
				Graphics_fillRectangle (my graphics, 0, 1, 0, 1);
				Graphics_setGrey (my graphics, 0.0);
				Graphics_flushWs (my graphics);
			}
			Graphics_updateWs (my graphics);
			if (experiment -> stimuliAreSounds) {
				autoMelderAudioSaveMaximumAsynchronicity saveMaximumAsynchronicity;
				if (experiment -> blankWhilePlaying)
					MelderAudio_setOutputMaximumAsynchronicity (kMelder_asynchronicityLevel_SYNCHRONOUS);
				ExperimentMFC_playStimulus (experiment, experiment -> stimuli [experiment -> trial]);
			}
		}
	} else if (experiment -> trial <= experiment -> numberOfTrials) {
		long iresponse;
		if (x > experiment -> ok_left && x < experiment -> ok_right &&
			y > experiment -> ok_bottom && y < experiment -> ok_top &&
			experiment -> responses [experiment -> trial] != 0 &&
			(experiment -> numberOfGoodnessCategories == 0 || experiment -> goodnesses [experiment -> trial] != 0))
		{
			do_ok (me);
		} else if (x > experiment -> replay_left && x < experiment -> replay_right &&
			y > experiment -> replay_bottom && y < experiment -> replay_top && my numberOfReplays < experiment -> maximumNumberOfReplays)
		{
			do_replay (me);
		} else if (x > experiment -> oops_left && x < experiment -> oops_right &&
			y > experiment -> oops_bottom && y < experiment -> oops_top && experiment -> trial > 1)
		{
			do_oops (me);
		} else if (experiment -> responses [experiment -> trial] == 0 || experiment -> ok_right > experiment -> ok_left) {
			for (iresponse = 1; iresponse <= experiment -> numberOfDifferentResponses; iresponse ++) {
				ResponseMFC response = & experiment -> response [iresponse];
				if (x > response -> left && x < response -> right && y > response -> bottom && y < response -> top && response -> name [0] != '\0') {
					experiment -> responses [experiment -> trial] = iresponse;
					experiment -> reactionTimes [experiment -> trial] = reactionTime;
					if (experiment -> responsesAreSounds) {
						ExperimentMFC_playResponse (experiment, iresponse);
					}
					if (experiment -> ok_right <= experiment -> ok_left && experiment -> numberOfGoodnessCategories == 0) {
						do_ok (me);
					} else {
						my broadcastDataChanged ();
						Graphics_updateWs (my graphics);
					}
				}
			}
			if (experiment -> responses [experiment -> trial] != 0 && experiment -> ok_right > experiment -> ok_left) {
				for (iresponse = 1; iresponse <= experiment -> numberOfGoodnessCategories; iresponse ++) {
					GoodnessMFC cat = & experiment -> goodness [iresponse];
					if (x > cat -> left && x < cat -> right && y > cat -> bottom && y < cat -> top) {
						experiment -> goodnesses [experiment -> trial] = iresponse;
						my broadcastDataChanged ();
						Graphics_updateWs (my graphics);
					}
				}
			}
		} else if (experiment -> responses [experiment -> trial] != 0) {
			Melder_assert (experiment -> ok_right <= experiment -> ok_left);
			for (iresponse = 1; iresponse <= experiment -> numberOfGoodnessCategories; iresponse ++) {
				GoodnessMFC cat = & experiment -> goodness [iresponse];
				if (x > cat -> left && x < cat -> right && y > cat -> bottom && y < cat -> top) {
					experiment -> goodnesses [experiment -> trial] = iresponse;
					do_ok (me);
				}
			}
		}
	} else {
		if (x > experiment -> oops_left && x < experiment -> oops_right &&
			y > experiment -> oops_bottom && y < experiment -> oops_top)
		{
			do_oops (me);
			return;
		}
		if (my iexperiment < my experiments -> size) {
			my iexperiment ++;
			if (! RunnerMFC_startExperiment (me)) {
				Melder_flushError (NULL);
				forget (me);
				return;
			}
		}
	}
}
コード例 #15
0
//make only one side move
possible_end_play_signal replay_controller::play_side() {

	DBG_REPLAY << "Status turn number: " << turn() << "\n";
	DBG_REPLAY << "Replay_Controller turn number: " << current_turn_ << "\n";
	DBG_REPLAY << "Player number: " << player_number_ << "\n";

	// If a side is empty skip over it.
	if (!current_team().is_empty()) {
		statistics::reset_turn_stats(current_team().save_id());

		possible_end_play_signal signal = play_controller::init_side(true);

		if (signal) {
			switch (boost::apply_visitor(get_signal_type(), *signal) ) {
				case END_TURN:
					return signal;
				case END_LEVEL:
					//VICTORY/DEFEAT end_level_exception shall not return to title screen
					LEVEL_RESULT res = boost::apply_visitor(get_result(), *signal);
					if ( res != VICTORY && res != DEFEAT ) return signal;
			}
		}

		DBG_REPLAY << "doing replay " << player_number_ << "\n";
		// if have reached the end we don't want to execute finish_side_turn and finish_turn
		// becasue we might not have enough data to execute them (like advancements during turn_end for example)

		try {
			if(do_replay() != REPLAY_FOUND_END_TURN) {
				// We reached the end of teh replay without finding and end turn tag.
				return boost::none;
			}
		} catch(end_level_exception& e){
			//VICTORY/DEFEAT end_level_exception shall not return to title screen
			if (e.result != VICTORY && e.result != DEFEAT) {
				return possible_end_play_signal(e.to_struct());
			}
		} catch (end_turn_exception & e) {
			return possible_end_play_signal(e.to_struct());
		}

		finish_side_turn();
	}

	player_number_++;

	if (static_cast<size_t>(player_number_) > gamestate_.board_.teams().size()) {
		//during the orginal game player_number_ would also be gamestate_.board_.teams().size(),
		player_number_ = gamestate_.board_.teams().size();
		finish_turn();
		gamestate_.tod_manager_.next_turn(*resources::gamedata);
		it_is_a_new_turn_ = true;
		player_number_ = 1;
		current_turn_++;
		gui_->new_turn();
	}

	// This is necessary for replays in order to show possible movements.
	gamestate_.board_.new_turn(player_number_);

	update_teams();
	update_gui();

	return boost::none;
}
コード例 #16
0
LRESULT APIENTRY MainWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {
        case WM_CREATE:
            create_toolbar(hwnd);
            create_term(hwnd);
            create_sysmenu(hwnd);

            return 0;

        case WM_SIZE:
            SendMessage(wndTB, TB_AUTOSIZE, 0, 0);
            get_def_size(LOWORD(lParam), HIWORD(lParam));
            return 0;

        case WM_DESTROY:
            PostQuitMessage(0);
            return 0;

        case WM_COMMAND:
            switch (LOWORD(wParam))
            {
            case BUT_OPEN:
                open_file();
                break;
            case BUT_REWIND:
            but_rewind:
                if (play_state==-1)
                    break;
                EnterCriticalSection(&vt_mutex);
                replay_pause();
                tr.tv_sec=0;
                tr.tv_usec=0;
                set_prog();
                replay_seek();
                LeaveCriticalSection(&vt_mutex);
                play_state=1;
                replay_resume();
                do_replay();
                break;
            case BUT_PAUSE:
                if (play_state==1)
                    goto but_unpause;
            but_pause:
                CancelWaitableTimer(timer);
                replay_pause();
                set_buttons(1);
                break;
            case BUT_PLAY:
                if (play_state>1)
                    goto but_pause;
            but_unpause:
                replay_resume();
                do_replay();
                set_buttons(1);
                break;
            case BUT_SELSTART:
                if (play_state==-1)
                    break;
                get_pos();
                selstart=tr;
                set_prog_sel();
                break;
            case BUT_SELEND:
                if (play_state==-1)
                    break;
                selend=tr;
                set_prog_sel();
                break;
            case BUT_EXPORT:
                if (play_state==-1)
                    break;
                if (tcmp(selstart, selend)>=0)
                    break;
                export_file();
                break;
            }
            return 0;

        case WM_SYSCOMMAND:
            switch (LOWORD(wParam))
            {
            default:
                return DefWindowProc(hwnd, uMsg, wParam, lParam);
            case BUT_FONT:
                choose_font();
            }
            return 0;

        case WM_HSCROLL:
            if ((HANDLE)lParam==wndSpeed)
                speed_scrolled();
            else if ((HANDLE)lParam==wndProg)
                prog_scrolled();
            return 0;

        case WM_KEYDOWN:
            switch (wParam)
            {
            case VK_ADD:
            case 'F':
                adjust_speed(+1);
                break;
            case VK_SUBTRACT:
            case 'S':
                adjust_speed(-1);
                break;
            case '1':
                SendMessage(wndSpeed, TBM_SETPOS, 1, 2);
                speed_scrolled();
                break;
            case 'Q':
                DestroyWindow(wndMain);
                break;
            case 'O':
                open_file();
                break;
            case VK_SPACE:
                switch (play_state)
                {
                case -1:
                    open_file();
                    break;
                case 0:
                    play_state=2;
                    goto but_rewind;
                case 1:
                    goto but_unpause;
                case 2:
                case 3:
                    goto but_pause;
                }
                break;
            case 'R':
                goto but_rewind;
                break;
            case VK_RIGHT:
                adjust_pos(+10);
                break;
            case VK_LEFT:
                adjust_pos(-10);
                break;
            case VK_UP:
                adjust_pos(+60);
                break;
            case VK_DOWN:
                adjust_pos(-60);
                break;
            case VK_PRIOR:
                adjust_pos(+600);
                break;
            case VK_NEXT:
                adjust_pos(-600);
                break;
            }
            return 0;

        case WM_SIZING:
            constrain_size((LPRECT)lParam);
            return 1;

        default:
            return DefWindowProc(hwnd, uMsg, wParam, lParam);
    }
    return 0;
}