Results 1 to 2 of 2

Thread: Messages not processed calling CL_DisplayMessageQueue::process() from another thread

  1. #1

    Default Messages not processed calling CL_DisplayMessageQueue::process() from another thread

    Hi

    I have a simple ClanLib 0.9 windowed app. It draw a background picture and a circle. The circle move randomly.

    It's using ClanLib 0.9 from the latest Subversion code.

    The message loop is as follow:

    Code:
    while(!Keyboard.get_keycode(CL_KEY_ESCAPE))
    {
    	Render();
    	CL_DisplayMessageQueue::process();
    	CL_System::sleep(10);
    }
    Render draw the BG picture, draw the circle and Flip.

    When I start moving the window by dragging the title bar, the process() function will not return until I stop dragging the window, meaning that the rendering will not happen while the window is moving.

    To solve this, I moved the message loop in another thread and call Render from the main thread. However with the message loop in another thread, it stop receiving messages and the window becomes unresponsive. The render continue to update the circle but the messages sent to the window (MOUSE_MOVE, etc) are not processed by ClanLib.


    So at first I have this
    Code:
    while(!Keyboard.get_keycode(CL_KEY_ESCAPE))
    {
    	Render();
    	CL_DisplayMessageQueue::process();
    	CL_System::sleep(10);
    }
    This works, but moving the window will pause the loop.

    Then I press escape, and continue to this code:

    Code:
    //Start Thread
    Trn(hThread = CreateThread(NULL, NULL, &ThreadProc, this, 0, &ThreadID));
    Code:
    //Thread for Message Loop
    DWORD WINAPI Screen::ThreadProc(void* lpParameter)
    {
    	return ((Screen*)lpParameter)->MessageLoop();
    }
    
    DWORD Screen::MessageLoop()
    {
    	while(!Keyboard.get_keycode(CL_KEY_ESCAPE))
    	{
    		CL_DisplayMessageQueue::process();
    		CL_System::sleep(10);
    	}
    	return 0;
    }
    The rendering continue from the main thread
    Code:
    while(true)
    {
    	lpScreen->Render();
    	Sleep(10);
    }
    This loop call CL_DisplayMessageQueue:rocess();
    which is

    Code:
    void CL_DisplayMessageQueue::process(int timeout)
    {
    	int time_start = CL_System::get_time();
    	while (true)
    	{
    		int time_elapsed = CL_System::get_time() - time_start;
    		int time_to_wait = timeout - time_elapsed;
    		if (time_to_wait < 0)
    			time_to_wait = 0;
    
    		std::vector<CL_KeepAliveObject *> objects = CL_KeepAlive::get_objects();
    		std::vector<CL_Event> events;
    		for (std::vector<CL_KeepAliveObject *>::size_type i = 0; i < objects.size(); i++)
    		{
    			events.push_back(objects[i]->get_wakeup_event());
    		}
    
    		int wakeup_reason = wait(events, timeout);
    
    		if (wakeup_reason >= 0)
    		{
    			objects[wakeup_reason]->process();
    		}
    		else if (wakeup_reason == -2)
    		{
    			do
    			{
    				CL_DisplayWindowMessage message = get_message();
    				dispatch_message(message);
    			}while (has_messages());		// There may be more than one message pending, so we have to process all of them here
    		}
    		else if (wakeup_reason == -1)
    		{
    			break;
    		}
    
    		if (time_to_wait == 0)
    			break;
    	}
    
    /*
    	while(has_messages())
    	{
    		CL_DisplayWindowMessage message = get_message();
    		dispatch_message(message);
    	}
    */
    }
    wakeup_reason will always receive -1, and no messages will be processed.



    Why is that?
    When it's from the same thread that created the window, it's fine.
    When it's from another thread, it stop receiving messages.

    How can I fix this?

    Thanks.

  2. #2
    ClanLib Developer
    Join Date
    Sep 2006
    Location
    Denmark
    Posts
    554

    Default

    The reason you cannot move the message processing to a second thread is because all windowing and GDI objects in Windows are tied to the thread that created them. This means that any HWND, HDC, HGLRC or other GDI resource handles (HFONT, HBRUSH, etc) belongs to the thread that created them.

    In particular for your situation, what happens is that the main thread creates the HWND and thus receives all messages related to this window. When you call process() in the second thread, it listens to messages for that thread and not the messages you'd like it to process. This is a design detail in how Win32 operates and there's nothing ClanLib can do about it. (Instead, ClanLib actually embraces this concept and dictates this rule to also apply to any clanDisplay object and CL_KeepAlive objects).

    About the process() function blocking when you move or resize a window in Windows:

    This is caused by a modal loop inside DefWindowProc. What happens is that when you click the caption bar, this generates a WM_NCLBUTTONDOWN. Since ClanLib does not handle this message, it ends up in the DefWindowProc. Here, Win32 itself starts a new GetMessage+DispatchMessage loop until the window move is complete. The only way to fix this problem you are describing is by ClanLib to implement its own move and resize code and handle WM_NCLBUTTONDOWN itself (doing it non-modal). That's a lot of work, but unfortunately the only way to fix that apps 'freeze' when you move or resize them.

Similar Threads

  1. Dictionary Additions Thread
    By Seth in forum Dungeon Scroll for PC and iPhone
    Replies: 39
    Last Post: 04-29-2016, 09:43 AM
  2. detect thread support
    By gergo in forum Official ClanLib SDK Forums
    Replies: 5
    Last Post: 02-13-2009, 10:12 AM
  3. Clanlib 9 CL_DisplayMessageQueue
    By jerkald in forum Official ClanLib SDK Forums
    Replies: 4
    Last Post: 10-03-2008, 10:20 AM
  4. Unofficial Novashell Scripting API Documentation Thread
    By Ian in forum Novashell Game Creation System
    Replies: 5
    Last Post: 01-08-2007, 07:54 AM

Bookmarks

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •