예제 #1
0
파일: appContext.cpp 프로젝트: nyorain/ny
X11AppContext::~X11AppContext()
{
    if(xDisplay_) ::XFlush(&xDisplay());

	xcb_ewmh_connection_wipe(&ewmhConnection());
	impl_.reset();

	if(xDummyWindow_) xcb_destroy_window(xConnection_, xDummyWindow_);
    if(xDisplay_) ::XCloseDisplay(&xDisplay());

	xDisplay_ = nullptr;
	xConnection_ = nullptr;
	xDefaultScreen_ = nullptr;
}
예제 #2
0
파일: glx.cpp 프로젝트: nyorain/ny
bool GlxContext::swapInterval(int interval, std::error_code& ec) const
{
	//TODO: check for interval < 0 and tear extensions not supported.
	ec.clear();

	if(!GLAD_GLX_EXT_swap_control || !glXSwapIntervalEXT)
	{
		ec = {GlContextErrc::extensionNotSupported};
		return false;
	}

	const GlSurface* currentSurface;
	GlContext::current(&currentSurface);

	auto currentGlxSurface = dynamic_cast<const GlxSurface*>(currentSurface);
	if(!currentGlxSurface)
	{
		// ec = {GlContextErrorCode::surfaceNotCurrent}; //TODO: add error for this case
		return false;
	}

	::glXSwapIntervalEXT(xDisplay(), currentGlxSurface->xDrawable(), interval);

	//TODO: handle possible error into ec

	return true;
}
예제 #3
0
파일: glx.cpp 프로젝트: nyorain/ny
GlxContext::~GlxContext()
{
	if(glxContext_)
	{
		std::error_code ec;
		if(!makeNotCurrent(ec))
			warning("ny::~GlxContext: failed to make the context not current: ", ec.message());

		::glXDestroyContext(xDisplay(), glxContext_);
	}
}
예제 #4
0
/*===========================================================================
===========================================================================*/
void SamplePosDet_Printf( CSamplePosDet *pMe, int nLine, int nCol, AEEFont fnt, uint32 dwFlags, 
                                const char *szFormat, ... )
{
   char              szBuf[64];
   va_list args;
   va_start( args, szFormat );

   (void)VSNPRINTF( szBuf, 64, szFormat, args );

   va_end( args );
   xDisplay( (AEEApplet *)pMe, nLine, nCol, fnt, dwFlags, szBuf );
}
예제 #5
0
파일: glx.cpp 프로젝트: nyorain/ny
bool GlxContext::makeNotCurrentImpl(std::error_code& ec)
{
	ec.clear();

    if(!::glXMakeCurrent(xDisplay(), 0, nullptr))
    {
		//TODO: handle error into ec
		warning("ny::GlxContext::makeNotCurrentImpl (glXMakeCurrent) failed");
        return false;
    }

    return true;
}
예제 #6
0
파일: glx.cpp 프로젝트: nyorain/ny
bool GlxContext::makeCurrentImpl(const GlSurface& surface, std::error_code& ec)
{
	ec.clear();

	auto drawable = dynamic_cast<const GlxSurface*>(&surface)->xDrawable();
    if(!::glXMakeCurrent(xDisplay(), drawable, glxContext_))
    {
		//TODO: handle error into ec
		warning("ny::GlxContext::makeCurrentImpl (glXMakeCurrent) failed");
        return false;
    }

    return true;
}
예제 #7
0
파일: appContext.cpp 프로젝트: nyorain/ny
xcb_atom_t X11AppContext::atom(const std::string& name)
{
	auto it = additionalAtoms_.find(name);
	if(it == additionalAtoms_.end())
	{
		auto cookie = xcb_intern_atom(xConnection_, 0, name.size(), name.c_str());
		xcb_generic_error_t* error;
		auto reply = xcb_intern_atom_reply(xConnection_, cookie, &error);
		if(error)
		{
			auto msg = x11::errorMessage(xDisplay(), error->error_code);
			warning("ny::X11AppContext::atom: failed to retrieve ", name, ": ", msg);
			free(error);
			return 0u;
		}

		it = additionalAtoms_.insert({name, reply->atom}).first;
		free(reply);
	}

	return it->second;
}
예제 #8
0
파일: appContext.cpp 프로젝트: nyorain/ny
void X11AppContext::processEvent(const x11::GenericEvent& ev)
{
	//macro for easier event creation for registered EventHandler
	#define EventHandlerEvent(T, W) \
		auto handler = eventHandler(W); \
		if(!handler) return; \
		auto event = T(handler);

	auto dispatch = [&](Event& event){
		if(event.handler) event.handler->handleEvent(event);
	};

	auto responseType = ev.response_type & ~0x80;
    switch(responseType)
    {

    case XCB_MOTION_NOTIFY:
    {
		auto& motion = reinterpret_cast<const xcb_motion_notify_event_t&>(ev);
		auto pos = nytl::Vec2i(motion.event_x, motion.event_y);
		mouseContext_->move(pos);

		EventHandlerEvent(MouseMoveEvent, motion.event);
        event.position = pos;
        event.screenPosition = nytl::Vec2i(motion.root_x, motion.root_y);

		dispatch(event);
		break;
    }

    case XCB_EXPOSE:
    {
		auto& expose = reinterpret_cast<const xcb_expose_event_t&>(ev);
        if(expose.count == 0)
		{
			EventHandlerEvent(DrawEvent, expose.window);
			dispatch(event);
		}

		break;
    }

    case XCB_MAP_NOTIFY:
    {
		auto& map = reinterpret_cast<const xcb_map_notify_event_t&>(ev);
		EventHandlerEvent(DrawEvent, map.window);
		dispatch(event);
		break;
    }

    case XCB_BUTTON_PRESS:
    {
		auto& button = reinterpret_cast<const xcb_button_press_event_t&>(ev);

		int scroll = 0;
		if(button.detail == 4) scroll = 1;
		else if(button.detail == 5) scroll = -1;

		if(scroll)
		{
			EventHandlerEvent(MouseWheelEvent, button.event);
			event.data = std::make_unique<X11EventData>(ev);
			event.value = scroll;

			mouseContext_->onWheel(*mouseContext_, scroll);
			dispatch(event);

			break;
		}

		auto b = x11ToButton(button.detail);
		mouseContext_->mouseButton(b, true);

		EventHandlerEvent(MouseButtonEvent, button.event);
		event.data = std::make_unique<X11EventData>(ev);
        event.button = b;
        event.position = nytl::Vec2i(button.event_x, button.event_y);
		event.pressed = true;

		dispatch(event);
		break;
    }

    case XCB_BUTTON_RELEASE:
    {
		auto& button = reinterpret_cast<const xcb_button_release_event_t&>(ev);
		if(button.detail == 4 || button.detail == 5) break;

		auto b = x11ToButton(button.detail);
		mouseContext_->mouseButton(b, false);

		EventHandlerEvent(MouseButtonEvent, button.event);
		event.data = std::make_unique<X11EventData>(ev);
        event.button = b;
        event.position = nytl::Vec2i(button.event_x, button.event_y);
		event.pressed = false;

		dispatch(event);
		break;
    }

    case XCB_ENTER_NOTIFY:
    {
		auto& enter = reinterpret_cast<const xcb_enter_notify_event_t&>(ev);
		auto wc = windowContext(enter.event);
		mouseContext_->over(wc);

		EventHandlerEvent(MouseCrossEvent, enter.event);
        event.position = nytl::Vec2i(enter.event_x, enter.event_y);
		event.entered = true;
		dispatch(event);

		break;
    }

    case XCB_LEAVE_NOTIFY:
    {
		auto& leave = reinterpret_cast<const xcb_enter_notify_event_t&>(ev);
		auto wc = windowContext(leave.event);
		if(mouseContext_->over() == wc) mouseContext_->over(nullptr);

		EventHandlerEvent(MouseCrossEvent, leave.event);
        event.position = nytl::Vec2i(leave.event_x, leave.event_y);
		event.entered = false;
		dispatch(event);

		break;
    }

    case XCB_FOCUS_IN:
    {
		auto& focus = reinterpret_cast<const xcb_focus_in_event_t&>(ev);
		auto wc = windowContext(focus.event);
		keyboardContext_->focus(wc);

		EventHandlerEvent(FocusEvent, focus.event);
		event.focus = true;
		dispatch(event);

		break;
    }

    case XCB_FOCUS_OUT:
    {
		auto& focus = reinterpret_cast<const xcb_focus_in_event_t&>(ev);
		auto wc = windowContext(focus.event);
		if(keyboardContext_->focus() == wc)keyboardContext_->focus(nullptr);

		EventHandlerEvent(FocusEvent, focus.event);
		event.focus = false;
		dispatch(event);

		break;
    }

    case XCB_KEY_PRESS:
    {
		auto& key = reinterpret_cast<const xcb_key_press_event_t&>(ev);

		EventHandlerEvent(KeyEvent, key.event);
		event.pressed = true;
		if(!keyboardContext_->keyEvent(key.detail, event)) bell();
		dispatch(event);

		break;
    }

    case XCB_KEY_RELEASE:
    {
		auto& key = reinterpret_cast<const xcb_key_press_event_t&>(ev);

		EventHandlerEvent(KeyEvent, key.event);
		event.pressed = false;
		if(!keyboardContext_->keyEvent(key.detail, event)) bell();
		dispatch(event);

		break;
    }

	case XCB_REPARENT_NOTIFY:
	{
		auto& reparent = reinterpret_cast<const xcb_reparent_notify_event_t&>(ev);
		auto wc = windowContext(reparent.window);
		if(wc) wc->reparentEvent();

		break;
	}

    case XCB_CONFIGURE_NOTIFY:
	{
		auto& configure = reinterpret_cast<const xcb_configure_notify_event_t&>(ev);

        //todo: something about window state
        auto nsize = nytl::Vec2ui(configure.width, configure.height);
        // auto npos = nytl::Vec2i(configure.x, configure.y); //positionEvent

		auto wc = windowContext(configure.window);
		if(wc) wc->sizeEvent(nsize);

        if(!eventHandler(configure.window)) break;

		/* TODO XXX !important
        if(any(windowContext(configure.window)->window().size() != nsize)) //sizeEvent
		{
			EventHandlerEvent(SizeEvent, configure.window);
			event->size = nsize;
			event->change = 0;
			dispatcher.dispatch(std::move(event));

			auto wc = windowContext(configure.window);
			if(!wc) return true;
			auto wevent = std::make_unique<SizeEvent>(wc);
			wevent->size = nsize;
			wevent->change = 0;
			dispatcher.dispatch(std::move(wevent));
		}

        if(any(windowContext(configure.window)->window().position() != npos))
		{
			EventHandlerEvent(PositionEvent, configure.window);
			event->position = npos;
			event->change = 0;
			dispatcher.dispatch(std::move(event));
		}
		*/

		break;
    }

    case XCB_CLIENT_MESSAGE:
    {
		auto& client = reinterpret_cast<const xcb_client_message_event_t&>(ev);
		auto protocol = static_cast<unsigned int>(client.data.data32[0]);
        if(protocol == atoms().wmDeleteWindow)
        {
			EventHandlerEvent(CloseEvent, client.window);
			dispatch(event);
        }

		break;
	}

	case 0u:
	{
		//an error occurred!
		int code = reinterpret_cast<const xcb_generic_error_t&>(ev).error_code;
		auto errorMsg = x11::errorMessage(xDisplay(), code);
		warning("ny::X11AppContext::processEvent: retrieved error code ", code, ", ", errorMsg);

		break;
	}

	default:
	{
		//check for xkb event
		if(ev.response_type == keyboardContext_->xkbEventType())
			keyboardContext_->processXkbEvent(ev);

		// May be needed for gl to work correctly... (TODO: test)
		// XLockDisplay(xDisplay_);
	    // auto proc = XESetWireToEvent(xDisplay_, ev.response_type & ~0x80, nullptr);
	    // if(proc)
		// {
	    //     XESetWireToEvent(xDisplay_, ev.response_type & ~0x80, proc);
	    //     XEvent dummy;
	    //     ev.sequence = LastKnownRequestProcessed(xDisplay_);
	    //     if(proc(xDisplay_, &dummy, (xEvent*) &ev)) //not handled
		// 	{
		// 		//TODO
		// 	}
	    // }
		//
		// XUnlockDisplay(xDisplay_);
	}

	}

	#undef EventHandlerEvent
}
예제 #9
0
파일: appContext.cpp 프로젝트: nyorain/ny
//appContext
X11AppContext::X11AppContext()
{
    //XInitThreads(); //todo, make this optional
	impl_ = std::make_unique<Impl>();

    xDisplay_ = ::XOpenDisplay(nullptr);
    if(!xDisplay_)
        throw std::runtime_error("ny::X11AppContext: could not connect to X Server");

    xDefaultScreenNumber_ = ::XDefaultScreen(xDisplay_);

 	xConnection_ = ::XGetXCBConnection(xDisplay_);
    if(!xConnection_ || xcb_connection_has_error(xConnection_))
		throw std::runtime_error("ny::X11AppContext: unable to get xcb connection");

	impl_->errorCategory = {*xDisplay_, *xConnection_};
	auto ewmhCookie = xcb_ewmh_init_atoms(&xConnection(), &ewmhConnection());

	//query information
	auto iter = xcb_setup_roots_iterator(xcb_get_setup(&xConnection()));
	for(auto i = 0; iter.rem; ++i, xcb_screen_next(&iter))
	{
	    if(i == xDefaultScreenNumber_)
		{
			xDefaultScreen_ = iter.data;
			break;
	    }
	}

	//This must be called because xcb is used to access the event queue
    ::XSetEventQueueOwner(xDisplay_, XCBOwnsEventQueue);

	//Generate an x dummy window that can e.g. be used for selections
	//This window remains invisible, i.e. it is not begin mapped
	xDummyWindow_ = xcb_generate_id(xConnection_);
    auto cookie = xcb_create_window_checked(xConnection_, XCB_COPY_FROM_PARENT, xDummyWindow_,
		xDefaultScreen_->root, 0, 0, 50, 50, 0, XCB_WINDOW_CLASS_INPUT_ONLY,
		XCB_COPY_FROM_PARENT, 0, nullptr);
	errorCategory().checkThrow(cookie, "ny::X11AppContext: create_window for dummy window failed");

	//Load all default required atoms
	auto& atoms = impl_->atoms;
	struct
	{
		xcb_atom_t& atom;
		const char* name;
	} atomNames[] =
	{
		{atoms.xdndEnter, "XdndEnter"},
		{atoms.xdndPosition, "XdndPosition"},
		{atoms.xdndStatus, "XdndStatus"},
		{atoms.xdndTypeList, "XdndTypeList"},
		{atoms.xdndActionCopy, "XdndActionCopy"},
		{atoms.xdndActionMove, "XdndActionMove"},
		{atoms.xdndActionAsk, "XdndActionAsk"},
		{atoms.xdndDrop, "XdndDrop"},
		{atoms.xdndLeave, "XdndLeave"},
		{atoms.xdndFinished, "XdndFinished"},
		{atoms.xdndSelection, "XdndSelection"},
		{atoms.xdndProxy, "XdndProxy"},
		{atoms.xdndAware, "XdndAware"},

		{atoms.clipboard, "CLIPBOARD"},
		{atoms.targets, "TARGETS"},
		{atoms.text, "TEXT"},
		{atoms.utf8string, "UTF8_STRING"},
		{atoms.fileName, "FILE_NAME"},

		{atoms.wmDeleteWindow, "WM_DELETE_WINDOW"},
		{atoms.motifWmHints, "_MOTIF_WM_HINTS"},

		{atoms.mime.textPlain, "text/plain"},
		{atoms.mime.textPlainUtf8, "text/plain;charset=utf8"},
		{atoms.mime.textUriList, "text/uri-list"},

		{atoms.mime.imageJpeg, "image/jpeg"},
		{atoms.mime.imageGif, "image/gif"},
		{atoms.mime.imagePng, "image/png"},
		{atoms.mime.imageBmp, "image/bmp"},

		{atoms.mime.imageData, "image/x-ny-data"},
		{atoms.mime.timePoint, "x-application/ny-time-point"},
		{atoms.mime.timeDuration, "x-application/ny-time-duration"},
		{atoms.mime.raw, "x-application/ny-raw-buffer"},
	};

	auto length = sizeof(atomNames) / sizeof(atomNames[0]);

	std::vector<xcb_intern_atom_cookie_t> atomCookies;
	atomCookies.reserve(length);

	for(auto& name : atomNames)
		atomCookies.push_back(xcb_intern_atom(xConnection_, 0, std::strlen(name.name), name.name));

	for(auto i = 0u; i < atomCookies.size(); ++i)
	{
		xcb_generic_error_t* error {};
		auto reply = xcb_intern_atom_reply(xConnection_, atomCookies[i], &error);
		if(reply)
		{
			atomNames[i].atom = reply->atom;
			free(reply);
			continue;
		}
		else if(error)
		{
			auto msg = x11::errorMessage(xDisplay(), error->error_code);
			free(error);
			warning("ny::X11AppContext: Failed to load atom ", atomNames[i].name, ": ", msg);
		}
	}

	//ewmh
	xcb_ewmh_init_atoms_replies(&ewmhConnection(), ewmhCookie, nullptr);

	//input
	keyboardContext_ = std::make_unique<X11KeyboardContext>(*this);
	mouseContext_ = std::make_unique<X11MouseContext>(*this);
}
예제 #10
0
파일: glx.cpp 프로젝트: nyorain/ny
GlxContext::GlxContext(const GlxSetup& setup, const GlContextSettings& settings)
	: setup_(&setup)
{
	auto major = settings.version.major;
	auto minor = settings.version.minor;

	if(major == 0 && minor == 0)
	{
		major = 4;
		minor = 5;
	}

	//test for logical errors
	if(settings.version.api != GlApi::gl)
		throw GlContextError(GlContextErrc::invalidApi, "ny::WglContext");

	if(major < 1 || major > 4 || minor > 5)
		throw GlContextError(GlContextErrc::invalidVersion, "ny::GlxContext");

	//config
	GlConfig glConfig;
	GLXFBConfig glxConfig;

	if(settings.config)
	{
		glConfig = setup.config(settings.config);
		glxConfig = setup.glxConfig(settings.config);
	}
	else
	{
		glConfig = setup.defaultConfig();
		glxConfig = setup.glxConfig(glConfig.id);
	}

	if(!glxConfig) throw GlContextError(GlContextErrc::invalidConfig, "ny::GlxContext");

	//shared
	GLXContext glxShareContext = nullptr;
	if(settings.share)
	{
		auto shareCtx = dynamic_cast<GlxContext*>(settings.share);
		if(!shareCtx)
			throw GlContextError(GlContextErrc::invalidSharedContext, "ny::EglContext");

		glxShareContext = shareCtx->glxContext();
	}

	//set a new error handler
    auto oldErrorHandler = ::XSetErrorHandler(&ctxErrorHandler);

    if(GLAD_GLX_ARB_create_context && glXCreateContextAttribsARB)
    {
		std::vector<int> contextAttribs;

		//profile
		contextAttribs.push_back(GLX_CONTEXT_PROFILE_MASK_ARB);
		if(!settings.compatibility) contextAttribs.push_back(GLX_CONTEXT_CORE_PROFILE_BIT_ARB);
		else contextAttribs.push_back(GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB);

		//forward compatible, debug
		auto flags = 0u;
		if(settings.forwardCompatible) flags |= GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB;
		if(settings.debug) flags |= GLX_CONTEXT_DEBUG_BIT_ARB;

		contextAttribs.push_back(GLX_CONTEXT_FLAGS_ARB);
		contextAttribs.push_back(flags);

		//version
		contextAttribs.push_back(GLX_CONTEXT_MAJOR_VERSION_ARB);
		contextAttribs.push_back(major);
		contextAttribs.push_back(GLX_CONTEXT_MINOR_VERSION_ARB);
		contextAttribs.push_back(minor);

		//end
		contextAttribs.push_back(0);

		glxContext_ = ::glXCreateContextAttribsARB(xDisplay(), glxConfig, glxShareContext,
			true, contextAttribs.data());

		if(!glxContext_ && !settings.forceVersion)
		{
			//those versions will be tried to create when the version specified in
			//the passed settings fails and the passed version should not be forced.
			constexpr std::pair<unsigned int, unsigned int> versionPairs[] =
				{{4, 5}, {3, 3}, {3, 2}, {3, 1}, {3, 0}, {1, 2}, {1, 0}};

			for(const auto& p : versionPairs)
			{
				contextAttribs[contextAttribs.size() - 4] = p.first;
				contextAttribs[contextAttribs.size() - 2] = p.second;
				glxContext_ = glXCreateContextAttribsARB(xDisplay(), glxConfig, glxShareContext,
					true, contextAttribs.data());

				if(glxContext_) break;
			}
		}
    }


    if(!glxContext_ && !settings.forceVersion)
	{
		warning("ny::GlxContext: failed to create modern context, trying legacy method");
		glxContext_ = ::glXCreateNewContext(xDisplay(), glxConfig, GLX_RGBA_TYPE,
			glxShareContext, true);
	}

    if(!glxContext_ && !settings.forceVersion)
	{
		glxContext_ = ::glXCreateNewContext(xDisplay(), glxConfig, GLX_RGBA_TYPE,
			glxShareContext, false);
	}

	::XSync(xDisplay(), false);
    ::XSetErrorHandler(oldErrorHandler);

	if(!glxContext_)
		throw std::runtime_error("ny::GlxContext: failed to create glx Context in any way.");

	if(!::glXIsDirect(xDisplay(), glxContext_))
		warning("ny::GlxContext: could only create indirect gl context -> worse performance");

	GlContext::initContext(GlApi::gl, glConfig, settings.share);
}