22 #include "../../SDL_internal.h" 24 #if SDL_VIDEO_DRIVER_X11 32 #include <X11/keysym.h> 36 #define SDL_FORK_MESSAGEBOX 1 37 #define SDL_SET_LOCALE 1 39 #if SDL_FORK_MESSAGEBOX 40 #include <sys/types.h> 47 #define MAX_TEXT_LINES 32 48 #define MIN_BUTTON_WIDTH 64 49 #define MIN_DIALOG_WIDTH 200 50 #define MIN_DIALOG_HEIGHT 100 52 static const char g_MessageBoxFontLatin1[] =
"-*-*-medium-r-normal--0-120-*-*-p-0-iso8859-1";
53 static const char g_MessageBoxFont[] =
"-*-*-medium-r-normal--*-120-*-*-*-*-*-*";
63 #define SDL_MAKE_RGB( _r, _g, _b ) ( ( ( Uint32 )( _r ) << 16 ) | \ 64 ( ( Uint32 )( _g ) << 8 ) | \ 65 ( ( Uint32 )( _b ) ) ) 67 typedef struct SDL_MessageBoxButtonDataX11 {
75 } SDL_MessageBoxButtonDataX11;
77 typedef struct TextLineData {
83 typedef struct SDL_MessageBoxDataX11
88 #if SDL_VIDEO_DRIVER_X11_XDBE 94 Atom wm_delete_message;
100 XFontStruct *font_struct;
104 TextLineData linedata[ MAX_TEXT_LINES ];
108 int button_press_index;
109 int mouse_over_index;
113 SDL_MessageBoxButtonDataX11 buttonpos[ MAX_BUTTONS ];
118 } SDL_MessageBoxDataX11;
122 IntMax(
int a,
int b )
124 return ( a > b ) ?
a :
b;
129 GetTextWidthHeight( SDL_MessageBoxDataX11 *
data,
const char *str,
int nbytes,
int *pwidth,
int *pheight )
131 if (SDL_X11_HAVE_UTF8) {
132 XRectangle overall_ink, overall_logical;
133 X11_Xutf8TextExtents(data->font_set, str, nbytes, &overall_ink, &overall_logical);
134 *pwidth = overall_logical.width;
135 *pheight = overall_logical.height;
137 XCharStruct text_structure;
138 int font_direction, font_ascent, font_descent;
139 X11_XTextExtents( data->font_struct, str, nbytes,
140 &font_direction, &font_ascent, &font_descent,
142 *pwidth = text_structure.width;
143 *pheight = text_structure.ascent + text_structure.descent;
149 GetHitButtonIndex( SDL_MessageBoxDataX11 *data,
int x,
int y )
152 int numbuttons = data->numbuttons;
153 SDL_MessageBoxButtonDataX11 *buttonpos = data->buttonpos;
155 for ( i = 0; i < numbuttons; i++ ) {
158 if ( ( x >= rect->
x ) &&
159 ( x <= ( rect->
x + rect->
w ) ) &&
161 ( y <= ( rect->
y + rect->
h ) ) ) {
171 X11_MessageBoxInit( SDL_MessageBoxDataX11 *data,
const SDL_MessageBoxData * messageboxdata,
int * pbuttonid )
178 if ( numbuttons > MAX_BUTTONS ) {
179 return SDL_SetError(
"Too many buttons (%d max allowed)", MAX_BUTTONS);
182 data->dialog_width = MIN_DIALOG_WIDTH;
183 data->dialog_height = MIN_DIALOG_HEIGHT;
184 data->messageboxdata = messageboxdata;
185 data->buttondata = buttondata;
186 data->numbuttons = numbuttons;
187 data->pbuttonid = pbuttonid;
189 data->display = X11_XOpenDisplay(
NULL );
190 if ( !data->display ) {
194 if (SDL_X11_HAVE_UTF8) {
195 char **missing =
NULL;
197 data->font_set = X11_XCreateFontSet(data->display, g_MessageBoxFont,
198 &missing, &num_missing,
NULL);
199 if ( missing !=
NULL ) {
200 X11_XFreeStringList(missing);
202 if ( data->font_set ==
NULL ) {
203 return SDL_SetError(
"Couldn't load font %s", g_MessageBoxFont);
206 data->font_struct = X11_XLoadQueryFont( data->display, g_MessageBoxFontLatin1 );
207 if ( data->font_struct ==
NULL ) {
208 return SDL_SetError(
"Couldn't load font %s", g_MessageBoxFontLatin1);
215 colorhints = g_default_colors;
220 data->color[
i ] = SDL_MAKE_RGB( colorhints[ i ].
r, colorhints[ i ].
g, colorhints[ i ].b );
228 X11_MessageBoxInitPositions( SDL_MessageBoxDataX11 *data )
232 int text_width_max = 0;
233 int button_text_height = 0;
234 int button_width = MIN_BUTTON_WIDTH;
240 TextLineData *plinedata = data->linedata;
242 for ( i = 0; i < MAX_TEXT_LINES; i++, plinedata++ ) {
244 char *lf =
SDL_strchr( (
char * )text,
'\n' );
249 plinedata->length = ( lf && ( i < MAX_TEXT_LINES - 1 ) ) ? ( lf -
text ) :
SDL_strlen( text );
250 plinedata->text =
text;
252 GetTextWidthHeight( data, text, plinedata->length, &plinedata->width, &height );
255 data->text_height = IntMax( data->text_height, height );
256 text_width_max = IntMax( text_width_max, plinedata->width );
258 if (lf && (lf > text) && (lf[-1] ==
'\r')) {
262 text += plinedata->length + 1;
270 data->text_height += 2;
274 for ( i = 0; i < data->numbuttons; i++ ) {
277 data->buttonpos[
i ].buttondata = &data->buttondata[
i ];
278 data->buttonpos[
i ].length =
SDL_strlen( data->buttondata[ i ].text );
280 GetTextWidthHeight( data, data->buttondata[ i ].text,
SDL_strlen( data->buttondata[ i ].text ),
281 &data->buttonpos[ i ].text_width, &height );
283 button_width = IntMax( button_width, data->buttonpos[ i ].text_width );
284 button_text_height = IntMax( button_text_height, height );
287 if ( data->numlines ) {
289 data->xtext = data->text_height;
290 data->ytext = data->text_height + data->text_height;
293 ybuttons = 3 * data->ytext / 2 + ( data->numlines - 1 ) * data->text_height;
296 data->dialog_width = IntMax( data->dialog_width, 2 * data->xtext + text_width_max );
297 data->dialog_height = IntMax( data->dialog_height, ybuttons );
300 ybuttons = button_text_height;
303 if ( data->numbuttons ) {
305 int width_of_buttons;
306 int button_spacing = button_text_height;
307 int button_height = 2 * button_text_height;
310 button_width += button_text_height;
313 width_of_buttons = data->numbuttons * button_width + ( data->numbuttons - 1 ) * button_spacing;
316 data->dialog_width = IntMax( data->dialog_width, width_of_buttons + 2 * button_spacing );
317 data->dialog_height = IntMax( data->dialog_height, ybuttons + 2 * button_height );
320 x = ( data->dialog_width - width_of_buttons ) / 2;
321 y = ybuttons + ( data->dialog_height - ybuttons - button_height ) / 2;
323 for ( i = 0; i < data->numbuttons; i++ ) {
325 data->buttonpos[
i ].rect.x =
x;
326 data->buttonpos[
i ].rect.y =
y;
327 data->buttonpos[
i ].rect.w = button_width;
328 data->buttonpos[
i ].rect.h = button_height;
331 data->buttonpos[
i ].x = x + ( button_width - data->buttonpos[
i ].text_width ) / 2;
332 data->buttonpos[
i ].y = y + ( button_height - button_text_height - 1 ) / 2 + button_text_height;
335 x += button_width + button_spacing;
344 X11_MessageBoxShutdown( SDL_MessageBoxDataX11 *data )
346 if ( data->font_set !=
NULL ) {
347 X11_XFreeFontSet( data->display, data->font_set );
348 data->font_set =
NULL;
351 if ( data->font_struct !=
NULL ) {
352 X11_XFreeFont( data->display, data->font_struct );
353 data->font_struct =
NULL;
356 #if SDL_VIDEO_DRIVER_X11_XDBE 357 if ( SDL_X11_HAVE_XDBE && data->xdbe ) {
358 X11_XdbeDeallocateBackBufferName(data->display, data->buf);
362 if ( data->display ) {
363 if ( data->window != None ) {
364 X11_XWithdrawWindow( data->display, data->window, data->screen );
365 X11_XDestroyWindow( data->display, data->window );
369 X11_XCloseDisplay( data->display );
370 data->display =
NULL;
376 X11_MessageBoxCreateWindow( SDL_MessageBoxDataX11 *data )
379 XSizeHints *sizehints;
380 XSetWindowAttributes wnd_attr;
381 Atom _NET_WM_WINDOW_TYPE, _NET_WM_WINDOW_TYPE_DIALOG, _NET_WM_NAME;
382 Display *display = data->display;
385 char *title_locale =
NULL;
387 if ( messageboxdata->
window ) {
391 data->screen = displaydata->
screen;
393 data->screen = DefaultScreen( display );
396 data->event_mask = ExposureMask |
397 ButtonPressMask | ButtonReleaseMask | KeyPressMask | KeyReleaseMask |
398 StructureNotifyMask | FocusChangeMask | PointerMotionMask;
399 wnd_attr.event_mask = data->event_mask;
401 data->window = X11_XCreateWindow(
402 display, RootWindow(display, data->screen),
404 data->dialog_width, data->dialog_height,
405 0, CopyFromParent, InputOutput, CopyFromParent,
406 CWEventMask, &wnd_attr );
407 if ( data->window == None ) {
413 X11_XSetTransientForHint( display, data->window, windowdata->
xwindow );
416 X11_XStoreName( display, data->window, messageboxdata->
title );
417 _NET_WM_NAME = X11_XInternAtom(display,
"_NET_WM_NAME", False);
421 XTextProperty titleprop;
422 Status status = X11_XStringListToTextProperty(&title_locale, 1, &titleprop);
425 X11_XSetTextProperty(display, data->window, &titleprop, XA_WM_NAME);
426 X11_XFree(titleprop.value);
430 #ifdef X_HAVE_UTF8_STRING 431 if (SDL_X11_HAVE_UTF8) {
432 XTextProperty titleprop;
433 Status status = X11_Xutf8TextListToTextProperty(display, (
char **) &messageboxdata->
title, 1,
434 XUTF8StringStyle, &titleprop);
435 if (status == Success) {
436 X11_XSetTextProperty(display, data->window, &titleprop,
438 X11_XFree(titleprop.value);
444 _NET_WM_WINDOW_TYPE = X11_XInternAtom(display,
"_NET_WM_WINDOW_TYPE", False);
445 _NET_WM_WINDOW_TYPE_DIALOG = X11_XInternAtom(display,
"_NET_WM_WINDOW_TYPE_DIALOG", False);
446 X11_XChangeProperty(display, data->window, _NET_WM_WINDOW_TYPE, XA_ATOM, 32,
448 (
unsigned char *)&_NET_WM_WINDOW_TYPE_DIALOG, 1);
451 data->wm_protocols = X11_XInternAtom( display,
"WM_PROTOCOLS", False );
452 data->wm_delete_message = X11_XInternAtom( display,
"WM_DELETE_WINDOW", False );
453 X11_XSetWMProtocols( display, data->window, &data->wm_delete_message, 1 );
456 XWindowAttributes attrib;
459 X11_XGetWindowAttributes(display, windowdata->
xwindow, &attrib);
460 x = attrib.x + ( attrib.width - data->dialog_width ) / 2;
461 y = attrib.y + ( attrib.height - data->dialog_height ) / 3 ;
462 X11_XTranslateCoordinates(display, windowdata->
xwindow, RootWindow(display, data->screen), x, y, &x, &y, &dummy);
468 x = dpydata->
x + (( dpy->
current_mode.
w - data->dialog_width ) / 2);
469 y = dpydata->
y + (( dpy->
current_mode.
h - data->dialog_height ) / 3);
471 x = ( DisplayWidth( display, data->screen ) - data->dialog_width ) / 2;
472 y = ( DisplayHeight( display, data->screen ) - data->dialog_height ) / 3 ;
475 X11_XMoveWindow( display, data->window, x, y );
477 sizehints = X11_XAllocSizeHints();
479 sizehints->flags = USPosition | USSize | PMaxSize | PMinSize;
482 sizehints->width = data->dialog_width;
483 sizehints->height = data->dialog_height;
485 sizehints->min_width = sizehints->max_width = data->dialog_width;
486 sizehints->min_height = sizehints->max_height = data->dialog_height;
488 X11_XSetWMNormalHints( display, data->window, sizehints );
490 X11_XFree( sizehints );
493 X11_XMapRaised( display, data->window );
495 #if SDL_VIDEO_DRIVER_X11_XDBE 497 if (SDL_X11_HAVE_XDBE) {
498 int xdbe_major, xdbe_minor;
499 if (X11_XdbeQueryExtension(display, &xdbe_major, &xdbe_minor) != 0) {
501 data->buf = X11_XdbeAllocateBackBufferName(display, data->window, XdbeUndefined);
513 X11_MessageBoxDraw( SDL_MessageBoxDataX11 *data, GC
ctx )
516 Drawable
window = data->window;
517 Display *display = data->display;
519 #if SDL_VIDEO_DRIVER_X11_XDBE 520 if (SDL_X11_HAVE_XDBE && data->xdbe) {
522 X11_XdbeBeginIdiom(data->display);
527 X11_XFillRectangle( display, window, ctx, 0, 0, data->dialog_width, data->dialog_height );
530 for ( i = 0; i < data->numlines; i++ ) {
531 TextLineData *plinedata = &data->linedata[
i ];
533 if (SDL_X11_HAVE_UTF8) {
534 X11_Xutf8DrawString( display, window, data->font_set, ctx,
535 data->xtext, data->ytext + i * data->text_height,
536 plinedata->text, plinedata->length );
538 X11_XDrawString( display, window, ctx,
539 data->xtext, data->ytext + i * data->text_height,
540 plinedata->text, plinedata->length );
544 for ( i = 0; i < data->numbuttons; i++ ) {
545 SDL_MessageBoxButtonDataX11 *buttondatax11 = &data->buttonpos[
i ];
548 int offset = ( ( data->mouse_over_index ==
i ) && ( data->button_press_index == data->mouse_over_index ) ) ? 1 : 0;
551 X11_XFillRectangle( display, window, ctx,
552 buttondatax11->rect.x - border, buttondatax11->rect.y - border,
553 buttondatax11->rect.w + 2 * border, buttondatax11->rect.h + 2 * border );
556 X11_XDrawRectangle( display, window, ctx,
557 buttondatax11->rect.x, buttondatax11->rect.y,
558 buttondatax11->rect.w, buttondatax11->rect.h );
560 X11_XSetForeground( display, ctx, ( data->mouse_over_index == i ) ?
564 if (SDL_X11_HAVE_UTF8) {
565 X11_Xutf8DrawString( display, window, data->font_set, ctx,
566 buttondatax11->x + offset,
567 buttondatax11->y + offset,
568 buttondata->
text, buttondatax11->length );
570 X11_XDrawString( display, window, ctx,
571 buttondatax11->x + offset, buttondatax11->y + offset,
572 buttondata->
text, buttondatax11->length );
576 #if SDL_VIDEO_DRIVER_X11_XDBE 577 if (SDL_X11_HAVE_XDBE && data->xdbe) {
578 XdbeSwapInfo swap_info;
579 swap_info.swap_window = data->window;
580 swap_info.swap_action = XdbeUndefined;
581 X11_XdbeSwapBuffers(data->display, &swap_info, 1);
582 X11_XdbeEndIdiom(data->display);
588 X11_MessageBoxEventTest(Display *display, XEvent *
event, XPointer arg)
590 const SDL_MessageBoxDataX11 *data = (
const SDL_MessageBoxDataX11 *) arg;
591 return ((event->xany.display == data->display) && (
event->xany.window == data->window)) ? True : False;
596 X11_MessageBoxLoop( SDL_MessageBoxDataX11 *data )
602 KeySym last_key_pressed = XK_VoidSymbol;
603 unsigned long gcflags = GCForeground | GCBackground;
609 if (!SDL_X11_HAVE_UTF8) {
611 ctx_vals.font = data->font_struct->fid;
614 ctx = X11_XCreateGC( data->display, data->window, gcflags, &ctx_vals );
616 return SDL_SetError(
"Couldn't create graphics context");
619 data->button_press_index = -1;
620 data->mouse_over_index = -1;
622 while( !close_dialog ) {
628 X11_XIfEvent( data->display, &e, X11_MessageBoxEventTest, (XPointer) data );
632 if ( ( e.type != Expose ) && X11_XFilterEvent( &e, None ) )
637 if ( e.xexpose.count > 0 ) {
650 data->button_press_index = -1;
651 data->mouse_over_index = -1;
657 const int previndex = data->mouse_over_index;
658 data->mouse_over_index = GetHitButtonIndex( data, e.xbutton.x, e.xbutton.y );
659 if (data->mouse_over_index == previndex) {
666 if ( e.xclient.message_type == data->wm_protocols &&
667 e.xclient.format == 32 &&
668 e.xclient.data.l[ 0 ] == data->wm_delete_message ) {
675 last_key_pressed = X11_XLookupKeysym( &e.xkey, 0 );
680 KeySym
key = X11_XLookupKeysym( &e.xkey, 0 );
683 if ( key != last_key_pressed )
686 if ( key == XK_Escape )
688 else if ( ( key == XK_Return ) || ( key == XK_KP_Enter ) )
695 for ( i = 0; i < data->numbuttons; i++ ) {
696 SDL_MessageBoxButtonDataX11 *buttondatax11 = &data->buttonpos[
i ];
698 if ( buttondatax11->buttondata->flags & mask ) {
699 *data->pbuttonid = buttondatax11->buttondata->buttonid;
709 data->button_press_index = -1;
710 if ( e.xbutton.button == Button1 ) {
712 data->button_press_index = GetHitButtonIndex( data, e.xbutton.x, e.xbutton.y );
718 if ( ( e.xbutton.button == Button1 ) && ( data->button_press_index >= 0 ) ) {
719 int button = GetHitButtonIndex( data, e.xbutton.x, e.xbutton.y );
721 if ( data->button_press_index == button ) {
722 SDL_MessageBoxButtonDataX11 *buttondatax11 = &data->buttonpos[
button ];
724 *data->pbuttonid = buttondatax11->buttondata->buttonid;
728 data->button_press_index = -1;
734 X11_MessageBoxDraw( data, ctx );
738 X11_XFreeGC( data->display, ctx );
746 SDL_MessageBoxDataX11
data;
757 origlocale = setlocale(LC_ALL,
NULL);
758 if (origlocale !=
NULL) {
760 if (origlocale ==
NULL) {
763 setlocale(LC_ALL,
"");
774 ret = X11_MessageBoxInit( &data, messageboxdata, buttonid );
776 ret = X11_MessageBoxInitPositions( &data );
778 ret = X11_MessageBoxCreateWindow( &data );
780 ret = X11_MessageBoxLoop( &data );
785 X11_MessageBoxShutdown( &data );
789 setlocale(LC_ALL, origlocale);
801 #if SDL_FORK_MESSAGEBOX 807 if (pipe(fds) == -1) {
808 return X11_ShowMessageBoxImpl(messageboxdata, buttonid);
815 return X11_ShowMessageBoxImpl(messageboxdata, buttonid);
816 }
else if (pid == 0) {
819 status = X11_ShowMessageBoxImpl(messageboxdata, buttonid);
820 if (write(fds[1], &status,
sizeof (
int)) !=
sizeof (
int))
822 else if (write(fds[1], buttonid,
sizeof (
int)) !=
sizeof (
int))
830 rc = waitpid(pid, &status, 0);
831 }
while ((rc == -1) && (errno == EINTR));
835 if ((rc == -1) || (!WIFEXITED(status)) || (WEXITSTATUS(status) != 0)) {
839 if (read(fds[0], &status,
sizeof (
int)) !=
sizeof (
int))
841 else if (read(fds[0], buttonid,
sizeof (
int)) !=
sizeof (
int))
848 return X11_ShowMessageBoxImpl(messageboxdata, buttonid);
GLdouble GLdouble GLdouble r
SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char int SDL_PRINTF_FORMAT_STRING const char const char SDL_SCANF_FORMAT_STRING const char return SDL_ThreadFunction const char void return Uint32 return Uint32 SDL_AssertionHandler void SDL_SpinLock SDL_atomic_t int int return SDL_atomic_t return void void void return void return int return SDL_AudioSpec SDL_AudioSpec return int int return return int SDL_RWops int SDL_AudioSpec Uint8 Uint32 * e
GLint GLint GLint GLint GLint x
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display dpy)
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
GLint GLint GLsizei width
RGB value used in a message box color scheme.
#define SDL_iconv_utf8_locale(S)
int SDL_X11_LoadSymbols(void)
SDL_DisplayMode current_mode
SDL_VideoDisplay * displays
GLint GLint GLint GLint GLint GLint y
GLenum GLuint GLenum GLsizei const GLchar * buf
const SDL_MessageBoxButtonData * buttons
MessageBox structure containing title, text, window, etc.
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display Drawable _Xconst char unsigned int unsigned int return Display Pixmap Pixmap XColor XColor unsigned int unsigned int return Display _Xconst char char int char return Display Visual unsigned int int int char unsigned int unsigned int in i)
#define SDL_assert(condition)
#define SDL_OutOfMemory()
static char text[MAX_TEXT_LENGTH]
GLint GLint GLsizei GLsizei height
SDL_VideoDisplay * SDL_GetDisplayForWindow(SDL_Window *window)
EGLSurface EGLNativeWindowType * window
GLint GLint GLsizei GLsizei GLsizei GLint border
SDL_VideoDevice * SDL_GetVideoDevice(void)
GLuint GLsizei GLsizei * length
GLboolean GLboolean GLboolean GLboolean a
const SDL_MessageBoxColorScheme * colorScheme
SDL_MessageBoxColor colors[SDL_MESSAGEBOX_COLOR_MAX]
GLboolean GLboolean GLboolean b
A rectangle, with the origin at the upper left.