162 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			162 lines
		
	
	
		
			4.5 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/*
 | 
						|
 *	A platform API implementation
 | 
						|
 *	Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com)
 | 
						|
 *
 | 
						|
 *	Distributed under the Boost Software License, Version 1.0.
 | 
						|
 *	(See accompanying file LICENSE_1_0.txt or copy at
 | 
						|
 *	http://www.boost.org/LICENSE_1_0.txt)
 | 
						|
 *
 | 
						|
 *	@file: nana/system/platform.cpp
 | 
						|
 *	@description:
 | 
						|
 *		this implements some API for platform-independent programming
 | 
						|
 *	@contributors:
 | 
						|
 *		Benjamin Navarro(pr#81)
 | 
						|
 */
 | 
						|
#include <nana/deploy.hpp>
 | 
						|
 | 
						|
#if defined(NANA_WINDOWS)
 | 
						|
	#include <windows.h>
 | 
						|
	#include "../detail/mswin/platform_spec.hpp"
 | 
						|
#elif defined(NANA_POSIX)
 | 
						|
	#include <time.h>
 | 
						|
	#include <errno.h>
 | 
						|
	#include <unistd.h>
 | 
						|
	#include <sys/time.h>
 | 
						|
	#include <sys/syscall.h>
 | 
						|
	#include <pthread.h>
 | 
						|
	#include <sys/stat.h>
 | 
						|
	#include <spawn.h>
 | 
						|
	#include <string.h>
 | 
						|
 | 
						|
static void posix_open_url(const char *url_utf8)
 | 
						|
{
 | 
						|
    extern char **environ;
 | 
						|
    const char *home = getenv("HOME");
 | 
						|
    std::string cheat(home);
 | 
						|
    cheat += "/.mozilla";
 | 
						|
    struct stat exists;
 | 
						|
 | 
						|
    // TODO: generalize this for chromium, opera, waterfox, etc.
 | 
						|
    // Most desktop environments (KDE, Gnome, Lumina etc.) provide a way to set
 | 
						|
    // your preferred browser - but there are more desktops than browsers.
 | 
						|
 | 
						|
    // Look for $HOME/.mozilla directory as strong evidence they use firefox.
 | 
						|
    if ( stat(cheat.c_str(), &exists) == 0 && S_ISDIR(exists.st_mode))
 | 
						|
    {
 | 
						|
        const char *path = "";
 | 
						|
        static const char *likely[2] = { "/usr/local/bin/firefox", "/usr/bin/firefox"};
 | 
						|
        if ( stat(likely[0], &exists) == 0 && S_ISREG(exists.st_mode))
 | 
						|
            path = likely[0];
 | 
						|
        else if ( stat(likely[1], &exists) == 0 && S_ISREG(exists.st_mode) )
 | 
						|
            path = likely[1];
 | 
						|
        else return;
 | 
						|
 | 
						|
        pid_t pid = 0;
 | 
						|
        static const char firefox[] = "firefox";
 | 
						|
        char name[sizeof firefox]{};
 | 
						|
        // argv does not like const-literals so make a copy.
 | 
						|
        strcpy(name, firefox);
 | 
						|
        char *argv[3] = {name, const_cast<char *>(url_utf8), nullptr};
 | 
						|
        posix_spawn(&pid, path, NULL, NULL, argv, environ);
 | 
						|
    }
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
namespace nana
 | 
						|
{
 | 
						|
namespace system
 | 
						|
{
 | 
						|
	//sleep
 | 
						|
	//@brief:	Suspend current thread for a specified milliseconds.
 | 
						|
	//			its precision is depended on hardware.
 | 
						|
	void sleep(unsigned milliseconds)
 | 
						|
	{
 | 
						|
#if defined(NANA_WINDOWS)
 | 
						|
		::Sleep(milliseconds);
 | 
						|
#elif defined(NANA_POSIX)
 | 
						|
		struct timespec timeOut, remains;
 | 
						|
		timeOut.tv_sec = milliseconds / 1000;
 | 
						|
		timeOut.tv_nsec = (milliseconds % 1000) * 1000000;
 | 
						|
		while(-1 == ::nanosleep(&timeOut, &remains))
 | 
						|
		{
 | 
						|
			if(errno == EINTR)
 | 
						|
				timeOut = remains;
 | 
						|
			else
 | 
						|
				break;
 | 
						|
		}
 | 
						|
#endif
 | 
						|
	}
 | 
						|
 | 
						|
	//this_thread_id
 | 
						|
	//@brief: get the identifier of calling thread.
 | 
						|
	thread_t this_thread_id()
 | 
						|
	{
 | 
						|
#if defined(NANA_WINDOWS)
 | 
						|
		return (thread_t)::GetCurrentThreadId();
 | 
						|
#elif defined(NANA_LINUX)
 | 
						|
		return (thread_t)::syscall(__NR_gettid);
 | 
						|
#elif defined(NANA_MACOS)
 | 
						|
		return (thread_t)::syscall(SYS_thread_selfid);
 | 
						|
#elif defined(NANA_POSIX)
 | 
						|
        return (thread_t)pthread_self();
 | 
						|
#endif
 | 
						|
	}
 | 
						|
 | 
						|
	unsigned long timestamp()
 | 
						|
	{
 | 
						|
#if defined(NANA_WINDOWS)
 | 
						|
		return ::GetTickCount();
 | 
						|
#elif defined(NANA_POSIX)
 | 
						|
		struct timeval tv;
 | 
						|
		::gettimeofday(&tv, 0);
 | 
						|
		return (tv.tv_sec * 1000 + tv.tv_usec / 1000);
 | 
						|
#endif
 | 
						|
	}
 | 
						|
 | 
						|
	bool get_async_mouse_state(int button)
 | 
						|
	{
 | 
						|
#if defined(NANA_WINDOWS)
 | 
						|
		bool swap = (::GetSystemMetrics(SM_SWAPBUTTON) != 0);
 | 
						|
		switch(button)
 | 
						|
		{
 | 
						|
		case 1: //Right
 | 
						|
			button = swap ? VK_LBUTTON : VK_RBUTTON;
 | 
						|
			break;
 | 
						|
		case 2:
 | 
						|
			button = VK_MBUTTON;
 | 
						|
			break;
 | 
						|
		default:
 | 
						|
			button = swap ? VK_RBUTTON : VK_LBUTTON;
 | 
						|
			break;
 | 
						|
		}
 | 
						|
 | 
						|
		return (::GetAsyncKeyState(button) != 0);
 | 
						|
#elif defined(NANA_POSIX)
 | 
						|
		static_cast<void>(button);	//eliminate unused parameter compiler warning.
 | 
						|
		return false;
 | 
						|
#endif
 | 
						|
	}
 | 
						|
 | 
						|
	//open an url through a default browser
 | 
						|
	void open_url(const std::string& url_utf8)
 | 
						|
	{
 | 
						|
		if(url_utf8.empty())
 | 
						|
			return;
 | 
						|
 | 
						|
#if defined(NANA_WINDOWS)
 | 
						|
		if(::ShellExecute(0, L"open", nana::to_wstring(url_utf8).c_str(), 0, 0, SW_SHOWNORMAL) < reinterpret_cast<HINSTANCE>(32))
 | 
						|
		{
 | 
						|
			//Because ShellExecute can delegate execution to Shell extensions (data sources, context menu handlers,
 | 
						|
			//verb implementations) that are activated using Component Object Model (COM), COM should be initialized
 | 
						|
			//before ShellExecute is called. Some Shell extensions require the COM single-threaded apartment (STA) type.
 | 
						|
			//In that case, COM should be initialized under WinXP.
 | 
						|
			nana::detail::platform_spec::co_initializer co_init;
 | 
						|
			::ShellExecute(0, L"open", nana::to_wstring(url_utf8).c_str(), 0, 0, SW_SHOWNORMAL);
 | 
						|
		}
 | 
						|
#elif defined(NANA_POSIX)
 | 
						|
        posix_open_url(url_utf8.c_str());
 | 
						|
#endif
 | 
						|
    }
 | 
						|
}//end namespace system
 | 
						|
}//end namespace nana
 |