The following sample code creates a new, “modern” window styled like an X-Plane 11 window. It demonstrates a number of the new XPLM300 APIs, including:


#include "XPLMDisplay.h"
#include "XPLMGraphics.h"
#include <string.h>
#include <stdio.h>
#if IBM
	#include <windows.h>
#endif
#if LIN
	#include <GL/gl.h>
#elif __GNUC__
	#include <OpenGL/gl.h>
#else
	#include <GL/gl.h>
#endif

#ifndef XPLM300
	#error This is made to be compiled against the XPLM300 SDK
#endif

static XPLMWindowID	g_window;

void				draw(XPLMWindowID in_window_id, void * in_refcon);
int					handle_mouse(XPLMWindowID in_window_id, int x, int y, int is_down, void * in_refcon);
void				receive_main_monitor_bounds(int inMonitorIndex, int inLeftBx, int inTopBx, int inRightBx, int inBottomBx, void * refcon);

int					dummy_mouse_handler(XPLMWindowID in_window_id, int x, int y, int is_down, void * in_refcon) { return 0; }
XPLMCursorStatus	dummy_cursor_status_handler(XPLMWindowID in_window_id, int x, int y, void * in_refcon) { return xplm_CursorDefault; }
int					dummy_wheel_handler(XPLMWindowID in_window_id, int x, int y, int wheel, int clicks, void * in_refcon) { return 0; }
void				dummy_key_handler(XPLMWindowID in_window_id, char key, XPLMKeyFlags flags, char virtual_key, void * in_refcon, int losing_focus) { }

static const char * g_pop_out_label = "Pop Out";
static const char * g_pop_in_label = "Pop In";
static float g_pop_button_lbrt[4]; // left, bottom, right, top
static float g_position_button_lbrt[4]; // left, bottom, right, top

static int	coord_in_rect(float x, float y, float * bounds_lbrt)  { return ((x >= bounds_lbrt[0]) && (x < bounds_lbrt[2]) && (y < bounds_lbrt[3]) && (y >= bounds_lbrt[1])); }


PLUGIN_API int XPluginStart(
						char *		outName,
						char *		outSig,
						char *		outDesc)
{
	strcpy(outName, "GuiSamplePlugin");
	strcpy(outSig, "xpsdk.examples.guisampleplugin");
	strcpy(outDesc, "A test plug-in that demonstrates the X-Plane 11 GUI plugin API.");

	// We're not guaranteed that the main monitor's lower left is at (0, 0)... we'll need to query for the global desktop bounds!
	int global_desktop_bounds[4]; // left, bottom, right, top
	XPLMGetScreenBoundsGlobal(&global_desktop_bounds[0], &global_desktop_bounds[3], &global_desktop_bounds[2], &global_desktop_bounds[1]);

	XPLMCreateWindow_t params;
	params.structSize = sizeof(params);
	params.left = global_desktop_bounds[0] + 50;
	params.bottom = global_desktop_bounds[1] + 150;
	params.right = global_desktop_bounds[0] + 350;
	params.top = global_desktop_bounds[1] + 450;
	params.visible = 1;
	params.drawWindowFunc = draw;
	params.handleMouseClickFunc = handle_mouse;
	params.handleRightClickFunc = dummy_mouse_handler;
	params.handleMouseWheelFunc = dummy_wheel_handler;
	params.handleKeyFunc = dummy_key_handler;
	params.handleCursorFunc = dummy_cursor_status_handler;
	params.refcon = NULL;
	params.layer = xplm_WindowLayerFloatingWindows;
	params.decorateAsFloatingWindow = 1;
	
	g_window = XPLMCreateWindowEx(&params);
	
	XPLMSetWindowPositioningMode(g_window, xplm_WindowPositionFree, -1);
	XPLMSetWindowGravity(g_window, 0, 1, 0, 1); // As the X-Plane window resizes, keep our size constant, and our left and top edges in the same place relative to the window's left/top
	XPLMSetWindowResizingLimits(g_window, 200, 200, 500, 500); // Limit resizing our window: maintain a minimum width/height of 200 boxels and a max width/height of 500
	XPLMSetWindowTitle(g_window, "Sample Window");

	return (g_window != NULL);
}

PLUGIN_API void	XPluginStop(void)
{
	// Since we created the window, we'll be good citizens and clean it up
	XPLMDestroyWindow(g_window);
	g_window = NULL;
}

PLUGIN_API void XPluginDisable(void) { }
PLUGIN_API int  XPluginEnable(void)  { return 1; }
PLUGIN_API void XPluginReceiveMessage(XPLMPluginID inFrom, int inMsg, void * inParam) { }

void	draw(XPLMWindowID in_window_id, void * in_refcon)
{
	char scratch_buffer[150];
	float col_white[] = {1.0, 1.0, 1.0};

	XPLMSetGraphicsState(
			0 /* no fog */,
			0 /* 0 texture units */,
			0 /* no lighting */,
			0 /* no alpha testing */,
			1 /* do alpha blend */,
			1 /* do depth testing */,
			0 /* no depth writing */
	);


	// We draw our rudimentary button boxes based on the height of the button text
	int char_height;
	XPLMGetFontDimensions(xplmFont_Proportional, NULL, &char_height, NULL);

	// We'll change the text of the pop-in/pop-out button based on our current state
	int is_popped_out = XPLMWindowIsPoppedOut(in_window_id);
	const char * pop_label = is_popped_out ? g_pop_in_label : g_pop_out_label;

	int l, t, r, b;
	XPLMGetWindowGeometry(in_window_id, &l, &t, &r, &b);

	// Draw our buttons
	{
		// Position the pop-in/pop-out button in the upper left of the window (sized to fit the
		g_pop_button_lbrt[0] = l + 10;
		g_pop_button_lbrt[3] = t - 15;
		g_pop_button_lbrt[2] = g_pop_button_lbrt[0] + XPLMMeasureString(xplmFont_Proportional, pop_label, strlen(pop_label)); // *just* wide enough to fit the button text
		g_pop_button_lbrt[1] = g_pop_button_lbrt[3] - (1.25f * char_height); // a bit taller than the button text

		// Position the "move to lower left" button just to the right of the pop-in/pop-out button
		const char * position_btn_text = "Move to Lower Left";
		g_position_button_lbrt[0] = g_pop_button_lbrt[2] + 30;
		g_position_button_lbrt[1] = g_pop_button_lbrt[1];
		g_position_button_lbrt[2] = g_position_button_lbrt[0] + XPLMMeasureString(xplmFont_Proportional, position_btn_text, strlen(position_btn_text));
		g_position_button_lbrt[3] = g_pop_button_lbrt[3];

		// Draw the boxes around our rudimentary buttons
		float green[] = {0.0, 1.0, 0.0, 1.0};
		glColor4fv(green);
		glBegin(GL_LINE_LOOP);
		{
			glVertex2i(g_pop_button_lbrt[0], g_pop_button_lbrt[3]);
			glVertex2i(g_pop_button_lbrt[2], g_pop_button_lbrt[3]);
			glVertex2i(g_pop_button_lbrt[2], g_pop_button_lbrt[1]);
			glVertex2i(g_pop_button_lbrt[0], g_pop_button_lbrt[1]);
		}
		glEnd();
		glBegin(GL_LINE_LOOP);
		{
			glVertex2i(g_position_button_lbrt[0], g_position_button_lbrt[3]);
			glVertex2i(g_position_button_lbrt[2], g_position_button_lbrt[3]);
			glVertex2i(g_position_button_lbrt[2], g_position_button_lbrt[1]);
			glVertex2i(g_position_button_lbrt[0], g_position_button_lbrt[1]);
		}
		glEnd();

		// Draw the button text (pop in/pop out)
		XPLMDrawString(col_white, g_pop_button_lbrt[0], g_pop_button_lbrt[1] + 4, (char *)pop_label, NULL, xplmFont_Proportional);

		// Draw the button text (reposition)
		XPLMDrawString(col_white, g_position_button_lbrt[0], g_position_button_lbrt[1] + 4, (char *)position_btn_text, NULL, xplmFont_Proportional);
	}

	// Draw a bunch of informative text
	{
		// Set the y position for the first bunch of text we'll draw to a little below the buttons
		int y = g_pop_button_lbrt[1] - 2 * char_height;

		// Display the total global desktop bounds
		{
			int global_desktop_lbrt[4];
			XPLMGetScreenBoundsGlobal(&global_desktop_lbrt[0], &global_desktop_lbrt[3], &global_desktop_lbrt[2], &global_desktop_lbrt[1]);
			sprintf(scratch_buffer, "Global desktop bounds: (%d, %d) to (%d, %d)", global_desktop_lbrt[0], global_desktop_lbrt[1], global_desktop_lbrt[2], global_desktop_lbrt[3]);
			XPLMDrawString(col_white, l, y, scratch_buffer, NULL, xplmFont_Proportional);
			y -= 1.5 * char_height;
		}

		// Display our bounds
		if(XPLMWindowIsPoppedOut(in_window_id)) // we are in our own first-class window, rather than "floating" within X-Plane's own window
		{
			int window_os_bounds[4];
			XPLMGetWindowGeometryOS(in_window_id, &window_os_bounds[0], &window_os_bounds[3], &window_os_bounds[2], &window_os_bounds[1]);
			sprintf(scratch_buffer, "OS Bounds: (%d, %d) to (%d, %d)", window_os_bounds[0], window_os_bounds[1], window_os_bounds[2], window_os_bounds[3]);
			XPLMDrawString(col_white, l, y, scratch_buffer, NULL, xplmFont_Proportional);
			y -= 1.5 * char_height;
		}
		else
		{
			int global_bounds[4];
			XPLMGetWindowGeometry(in_window_id, &global_bounds[0], &global_bounds[3], &global_bounds[2], &global_bounds[1]);
			sprintf(scratch_buffer, "Window bounds: %d %d %d %d", global_bounds[0], global_bounds[1], global_bounds[2], global_bounds[3]);
			XPLMDrawString(col_white, l, y, scratch_buffer, NULL, xplmFont_Proportional);
			y -= 1.5 * char_height;
		}

		// Display whether we're in front of our our layer
		{
			sprintf(scratch_buffer, "In front? %s", XPLMIsWindowInFront(in_window_id) ? "Y" : "N");
			XPLMDrawString(col_white, l, y, scratch_buffer, NULL, xplmFont_Proportional);
			y -= 1.5 * char_height;
		}

		// Display the mouse's position info text
		{
			int mouse_global_x, mouse_global_y;
			XPLMGetMouseLocationGlobal(&mouse_global_x, &mouse_global_y);
			sprintf(scratch_buffer, "Draw mouse (global): %d %d\n", mouse_global_x, mouse_global_y);
			XPLMDrawString(col_white, l, y, scratch_buffer, NULL, xplmFont_Proportional);
			y -= 1.5 * char_height;
		}
	}

}

int	handle_mouse(XPLMWindowID in_window_id, int x, int y, XPLMMouseStatus is_down, void * in_refcon)
{
	if(is_down == xplm_MouseDown)
	{
		const int is_popped_out = XPLMWindowIsPoppedOut(in_window_id);
		if (!XPLMIsWindowInFront(in_window_id))
		{
			XPLMBringWindowToFront(in_window_id);
		}
		else if(coord_in_rect(x, y, g_pop_button_lbrt)) // user clicked the pop-in/pop-out button
		{
			XPLMSetWindowPositioningMode(in_window_id, is_popped_out ? xplm_WindowPositionFree : xplm_WindowPopOut, 0);
		}
		else if(coord_in_rect(x, y, g_position_button_lbrt)) // user clicked the "move to lower left" button
		{
			// If we're popped out, and the user hits the "move to lower left" button,
			// we need to move them to the lower left of their OS's desktop space (units are pixels).
			// On the other hand, if we're a floating window inside of X-Plane, we need
			// to move to the lower left of the X-Plane global desktop (units are boxels).
			void (* get_geometry_fn)(XPLMWindowID, int *, int *, int *, int *) = is_popped_out ? &XPLMGetWindowGeometryOS : &XPLMGetWindowGeometry;
			int lbrt_current[4];
			get_geometry_fn(in_window_id, &lbrt_current[0], &lbrt_current[3], &lbrt_current[2], &lbrt_current[1]);

			int h = lbrt_current[3] - lbrt_current[1];
			int w = lbrt_current[2] - lbrt_current[0];
			void (* set_geometry_fn)(XPLMWindowID, int, int, int, int) = is_popped_out ? &XPLMSetWindowGeometryOS : &XPLMSetWindowGeometry;

			// Remember, the main monitor's origin is *not* guaranteed to be (0, 0), so we need to query for it in order to move the window to its lower left
			int bounds[4] = {0}; // left, bottom, right, top
			if(is_popped_out)
			{
				XPLMGetScreenBoundsGlobal(&bounds[0], &bounds[3], &bounds[2], &bounds[1]);
			}
			else
			{
				XPLMGetAllMonitorBoundsOS(receive_main_monitor_bounds, bounds);
			}

			set_geometry_fn(in_window_id, bounds[0], bounds[1] + h, bounds[0] + w, bounds[1]);
		}
	}
	return 1;
}

void receive_main_monitor_bounds(int inMonitorIndex, int inLeftBx, int inTopBx, int inRightBx, int inBottomBx, void * refcon)
{
	int * main_monitor_bounds = (int *)refcon;
	if(inMonitorIndex == 0) // the main monitor
	{
		main_monitor_bounds[0] = inLeftBx;
		main_monitor_bounds[1] = inBottomBx;
		main_monitor_bounds[2] = inRightBx;
		main_monitor_bounds[3] = inTopBx;
	}
}

55 comments on “X-Plane 11 Window API Sample

  1. Tyler,

    This may be a stupid question, but do these “modern” windows support widget features such as text boxes, sliders, buttons (like the ones on the map) etc? If so, how would I go about implementing them into the window?

    Thanks, Jake.

    1. Sorry, forgot to also ask if the old widgets will be compatible will Vulkan (and will OpenGL also still be supported for plugins that want to use it?)
      Thanks.

      1. We just don’t know yet what the transition to new graphics APIs will be like. The most we can say is that we’ll do our best to make old code backward compatible.

      2. Our goal _is_ compatibility between legacy widget code and Vulkan – if it’s possible, we’ll do it. We have not proven it’s possible using all drivers though.

    2. Under the hood, XPWidgets uses the XPLMCreateWindowEx() API, so XPWidget windows will get scaling for free. But, we have not yet exposed our internal GUI framework to the SDK, so there’s no straightforward way to create text boxes, sliders, etc. that match the X-Plane 11 styling.

      1. Hi Tyler

        I am interested in knowing whether you are planning to expose your internal GUI framework to the SDK or not, as it would make plug-ins look and feel more natural.

  2. Hi Tyler,

    Will the classes in the SDKs “Wrappers” folder will support the new XPLM300 functions, like: XPLMCreateWindowEx ?

    What I See now from the SDK is that it supports the XPLMCreaeteWindow() and not the new extensions.

    Thanks
    Saar

    1. Uh… since you compile the wrapper yourself, you could just change the implementation. (Unless you’re, like, sharing a common base class with plugins not under your control, perhaps?) If I’m missing something, please let me know.

      1. Hi,

        I did modify it to reflect the new functionality, but was not sure if that was a safe move, since I prefer to stick to what LR dim as their standard (tried the inheritance approach first but got little confused).
        From your answer, I understand that the wrapper is given as is, and we are allowed to modify it to our own needs.

        One last thing,
        When I read your examples, which are really helpful, I can’ say I’m not concern with the new coming APIs, which are Vulkan and Metal. I mean, today I have to learn and implement the GL approach, but once you will switch to the “newer” APIs you will have to learn two different graphical APIs and their own implementations.

        My humble suggestion is that LR will create their own XPSDK wrappers so we will just have to use your part of the graphical API. So if I need to just draw simple primitive lines to create “cube” or “box” I will just need to call XPSDK_PRIMITIVE_BOX, send my values and the SDK will handle the correct commands in the respective active API.
        I believe this is not a simple suggestion or request, but I really think it is important to allow plugin programmers to deal with the core functionality of their plugins instead of be “know it all” persons.

        Thanks you for your time and great work.
        Saar

        1. Having an X-Plane “wrapper” around the underlying graphics API (similar to Skia) is indeed something we’re considering. Certainly as the world gets more multithreaded, the penalty to having plugins draw directly (and synchronously) gets worse—hence the new object instancing APIs, which aim to help get plugins out of the 3-D drawing path. As I told another commenter, though, until we actually have a prototype of the new graphics APIs, it’s hard to say what the compatibility situation will be for old drawing code.

  3. Hi Tyler,

    Embarrassing as it is, I have a question regarding your C code example, specifically around the code below, I just can’t wrap my head and understand it. get_geometry_fn is not really a function, but it behaves like one and the declaration is internal to the code body (remind of lambda expression).
    Is it OK for you to explain this syntax ?

    void (* get_geometry_fn)(XPLMWindowID, int *, int *, int *, int *) = is_popped_out ? &XPLMGetWindowGeometryOS : &XPLMGetWindowGeometry;
    int lbrt_current[4];
    get_geometry_fn(in_window_id, &lbrt_current[0], &lbrt_current[3], &lbrt_current[2], &lbrt_current[1]);

    Thanks
    Saar

    1. For those who don’t speak “1970’s compiler):
      void foo(int a, int b); /* this is a function */
      void (*foo)(int a, int b); /* this is a POINTER to a function with the same signature as foo.)
      Tyler is being very clever: he’s declared get_geometry_fn as a function pointer – and taking advantage of the fact that the two XPM routines to get window geometry (the OS one and in-monitor one) have the SAME prototypes – so we can save a ptr to the right function based on what his window is doing, and then just call it.

      He could also have just written an if statement. 🙂 But…like Sidney and Philipp, Tyler is under 40 and thus sometimes writes clever code.

      I, however, am over 40, and have basically stopped writing clever code due to the large number of years I have spent…debugging my own clever code. 🙂 🙂 🙂

          1. I think I’ll just use:

            int lbrt_current[4];

            if (is_popped_out)
            XPLMGetWindowGeometryOS(in_window_id, &lbrt_current[0], &lbrt_current[3], &lbrt_current[2], &lbrt_current[1]);
            else
            XPLMGetWindowGeometry(in_window_id, &lbrt_current[0], &lbrt_current[3], &lbrt_current[2], &lbrt_current[1]);

            And it is nice to see you use “auto”, the new compiler directives can really make coding easier…

            By the way, is there a transparent window option like the XPSDK2xx ?

            Cheers
            Saar

  4. Hi Tyler,

    I think I tried it, but there is no real transparent window it is more “an uninitialized pointer to a transparent window” (ok enough of these kind of jokes 😉 ).
    The transparency I’m looking for is like XPSDK200 transparent widget. In XPSDK300 the transparency is full, meaning there is no decoration or texture for the window. I want to still have the texture of the window but with high level of transparency, just like the “communication messages” we see from ATC.

    Hope that is clearer.
    Thanks
    Saar

    1. If we draw nothing you can always add your own level of transparency by drawing yourelf. Are you referring to having access to our translucent anti-aliased round rect?

  5. So that what it is ?
    translucent anti-aliased round rectangle ?

    Again I have very little experience with OpenGL except of what I learned during my plugin programming, and not all what I see I can translate or break to its components.
    If I understand correctly, you “just” draw a GL rectangle, I guess you “fill” it with color and define transparency ?

    The pros in XDK200 widget system was that your transparent window also managed mouse, but I guess in SDK300 if I want to move a transparent window I would have to manage all aspects of it and it is not part of the SDK responsibilities (again I’m referring to decorateAsFloatingWindow = false).

    Thanks
    Saar

    1. Right… if you have an undecorated window, you’re responsible for managing everything: you draw it, you decide how click handlers work, etc. The advantage of a decorated window is that we’ll at least give you a background and handle click-and-drag on the title bar for you.

  6. Hello,

    I’ve some topics to check with you :

    For information, I’m creating my windows with theXPLMCreateWindow_t.decorateAsFloatingWindow = false; to have my own windows design. I can’t send photo here 🙁

    • The Window callback handleMouseWheelFunc do not function well. The “wheel” parameters has more values than 0 and 1 and “clicks” parameter receive always 0 (Zero).

    • The function XPLMSetWindowTitle do not set the window name for a window created has theXPLMCreateWindow_t.decorateAsFloatingWindow = false;

    • Impossible to use OpenGL slScissor function inside a floating window, it’s clip all (when the window is XPLMSetWindowPositioningMode( mWindowID, xplm_WindowPopOut, -1);) :
    slScissor( left, bottom + 10, right – left, top – bottom – 32);
    glEnable( GL_SCISSOR_TEST);

    // Draw …

    glDisable( GL_SCISSOR_TEST);

    • Impossible to manually change the floating windows size if
    theXPLMCreateWindow_t.decorateAsFloatingWindow = false;
    XPLMSetWindowPositioningMode( mWindowID, xplm_WindowPopOut, -1);

    • On previous SDK, when you have 2 windows (one on the front and the other on the back) you can click and drag the background window. Now, you need to click one time to activate the background window and after that you can drag it.

    • On previous windows system, I’m creating a popup menu by make a other window front the first. But now, how could I process when my window is Floating ?

    Thanks in advance for your help,
    Cheers
    Stef

    1. Re: the mouse wheel, I’m looking into this…

      Re: XPLMSetWindowTitle(), for an undecorated window, it’s expected that the title is not displayed. If you want a title to be drawn, you have to draw it! 🙂

      Re: scissors, there’s a lot of fine print here (and it’s something we rrrrreally should make easier). Your window uses X-Plane global desktop coordinates, but the GL scissors functions need window coordinates. You’ll need to use gluProject(), which itself depends on glGetXXX() calls for the projection matrix, modelview matrix, etc. This is pretty expensive for the driver, which is why we really need an SDK call to get this stuff.

      When you say it’s impossible to manually change the floating window’s size, I assume you mean it’s impossible for the user to click-and-drag, right? Again, that’s as expected—if you want an undecorated window, you have to handle the mouse clicks.

      Requiring a click to “activate” a background window matches the behavior of the rest of the new X-Plane 11 UI (and the behavior of real operating system windows), so that’s intended.

      For a popup menu, you should be able to simply create a new window and bring it to the front (via XPLMBringWindowToFront()). Are you saying that’s not working?

      1. Dear Tyler,

        First at all thanks for your time and replies !

        To be simple and let you win a precious time, I’ve make a little video. I hope it could help you enough to understand, else, let me know.
        //youtu.be/Mf0Z6x0VK1Y

        Please remain I would like my windows have my appearance and not the X-Plane windows appearance.

        • “activate” a background window : Ok, Thanks understand, it is fine.

        • « When you say it’s impossible to manually change the floating window’s size » : Please take a look on my little video.

        • « Re: XPLMSetWindowTitle(), for an undecorated window » : Please take a look on my little video.

        • « For a popup menu » : I understand your reply, but what’s append if I do that when the window if detached ? my popup will be with a drag bar and I can’t control anything ?!

        • « Re: scissors » : Nice information. When do you expect to have it inside XPLM3 and XP11.10b? it is mandatory for me to progress 🙁

        Again, your help is really appreciated because without it, I can’t make my plugin. THANKS A LOT
        Feel free to write to my email, I’ll provide you all you could need.

        Cheers
        Stef

        1. I think you’re on to a number of unimplemented features.

          I’ve filed a bug for:
          – the inability to resize popped out windows
          – popped out windows not respecting resizing limits
          – missing window titles in the operating system windows

          The bug will be listed as XPD-8418 in the release notes.

          Re: the popup menu, can you get me a minimal code example that demonstrates the issue? That would help make sure we’re on the same page.

          Re: scissors, I don’t have an ETA. I suggest implementing it by hand for now.

    2. Wooooow, yeah, I confirm XPLMHandleMouseWheel_f is massively broken in 11.10. It looks like we accidentally swapped the “wheel” and “clicks” parameters… don’t try to code around this—I’ll get it fixed for the next beta!

  7. Hi again,
    I have two questions (with a short story each):

    1. I saw that in XP11 you are using different sizes of fonts or some kind of TTF rendering ? I was wondering if you can expose this to plugin builders, since the default font size is good for “average eyesight” person but it is quite hard to read from distance (~ 1 meter). It is also quite useless when you want to emphasize parts of sentences or create titles (very monotonic look)

    2. Since I failed miserably drawing TTF in OpenGL (it was drawn flipped and I did not know how to flip it 🙁 ), I implemented a “simple” library to handle some OpenGL staff. The problem with external libraries is that you need to pass all windows events so they will know how to handle their internal drawing and events.
    Problem: If you want to draw a window and “catch” mouse/keyboard events, you must create a window using “XPLMCreateWindowEx” and “overlay it” with your library window so it will be hidden 100% of the time.

    Question: Can you allow mouse/key event to be “catch” by plugin code even if there is no XPSDK window? That way I can just send any event to the library and it will handle its internal events according to the information I expose it.

    Thanks

    1. Re: #1, we do plan to address fonts at some point, but it will be in the context of a total overhaul of the UI framework. Short term, you’ll have to do your own font drawing if you want other fonts.

      Re: #2, we would definitely expect your window classes to have to pass mouse & keyboard events through to whatever library utilities you have. Having a global intercept strikes me as the wrong solution for this.

      1. “we do plan to address fonts at some point, but it will be in the context of a total overhaul of the UI framework”, I’m impatient to have it because loading and drawing font from plugin sources is a bit hard on cross plateform 🙁

        1. I totally agree stef, though, as Tyler said, it is a long way to implement as an API.
          Today I’m using Nuklear library to handle 99% of UI, if I did know how to display Fonts, I would just use XPSDK.
          In the mean time, Thank you Philip for referencing the font manager open source code, I’ll take a look though I think that my main problem is the rendering, my fonts where upside down and projecting them was not the answer (in my case).

          Cheers
          Saar

  8. Hello,

    I’m trying to get this sample project to work.
    I’m able to download the project and make it build using Visual Studio 2010 (we did not modify the downloaded project).
    Then, I add the win.xpl file here : “/Resources/plugins/X-Plane-11-Window-API-Sample/64/win.xpl”

    After launching XPlane11, the window is not showing and the log file says :
    “D:\Steam/steamapps/common/X-Plane 11/Resources/plugins/X-Plane-11-Window-API-Sample/64/win.xpl> : Error Code = 127 : The specified procedure could not be found.”

    Any help would be appreciated, thanks !

    Best regards

    1. I can’t reproduce this. The error indicates that one of the five required callbacks is missing from the plugin. Since the sample code implements all 5, I suspect the error either comes from some another plugin, or it’s caused by a modification you made to the code.

  9. Is there any way to register a callback for the user user closing the window? If not: What’s the best way of detecting that event?

  10. Thanks for updating the window behavior – it works well for me.

    Question: Is there any way to query which windows other plugins have opened, their window geometry, so I can avoid overlapping windows when I create one?

    Thanks for any help.

  11. Hi,
    is it now possible to add text boxes, sliders etc. to XP11 styled windows? Without those, the interaction with such windows is pretty limited.

    best regards

  12. Hi Tyler.

    Do you have any news about the new SDK for Modern UI? I’m coding a new plugin and it would be awsome to make a UI that has the same “look and feel” of the game.

      1. I had the same question.

        Thirty-three months after this new window API was announced and there is still no modern widget library for third party developers. It seems like a lot of trouble for every single developer to roll their own widget library, trying to visually emulate what Laminar Research has already coded but not made “SDK wrappers” for.

        Sadly, I lack the energy I once had. So, I punted and I’m still using the legacy XP widgets. They look kinda dated, and my old eyes have to squint at the tiny, low-contrast font, but it works. I guess that’s enough for an open-source project. 😉

        1. Same problem here =(
          Working on a new plugin and still have to use the old windows for anything else than simple text display

      2. Isn’t it possible to make the old window system work in VR until you have the new UI SDK finished? I have so many plugins that use the old system, it’s going to take months trying to have to code everything including basic widgets from scratch.

  13. How can you tell when the window is closed so that you cleanup things like key sniffers which still seem to run after you close the window?

  14. Hi Tyler,
    I have a question. How can I protect the window from closing? I would like to disable X in the right top corner but can’t find the solution. Is it possible?
    Also, I am wondering if the changing font/text size will be available soon? I found the PPL library but I am confused about how to use it. Is it possible to post here a Sample of changing the font – the same as some samples on this site (audio and etc) which are just awesome and helpful!

    Thanks 🙂

Leave a Reply

Your email address will not be published. Required fields are marked *

Please do not report bugs in the blog comments.
Only bugs reported via the X-Plane Bug Reporter are tracked.