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 MIN_BUTTON_WIDTH 64 48 #define MIN_DIALOG_WIDTH 200 49 #define MIN_DIALOG_HEIGHT 100 51 static const char g_MessageBoxFontLatin1[] =
"-*-*-medium-r-normal--0-120-*-*-p-0-iso8859-1";
52 static const char g_MessageBoxFont[] =
"-*-*-medium-r-normal--*-120-*-*-*-*-*-*";
62 #define SDL_MAKE_RGB( _r, _g, _b ) ( ( ( Uint32 )( _r ) << 16 ) | \ 63 ( ( Uint32 )( _g ) << 8 ) | \ 64 ( ( Uint32 )( _b ) ) ) 66 typedef struct SDL_MessageBoxButtonDataX11 {
74 } SDL_MessageBoxButtonDataX11;
76 typedef struct TextLineData {
82 typedef struct SDL_MessageBoxDataX11
87 #if SDL_VIDEO_DRIVER_X11_XDBE 93 Atom wm_delete_message;
99 XFontStruct *font_struct;
103 TextLineData *linedata;
107 int button_press_index;
108 int mouse_over_index;
112 SDL_MessageBoxButtonDataX11 buttonpos[ MAX_BUTTONS ];
117 } SDL_MessageBoxDataX11;
121 IntMax(
int a,
int b )
123 return ( a > b ) ? a :
b;
128 GetTextWidthHeight( SDL_MessageBoxDataX11 *
data,
const char *str,
int nbytes,
int *pwidth,
int *pheight )
130 if (SDL_X11_HAVE_UTF8) {
131 XRectangle overall_ink, overall_logical;
132 X11_Xutf8TextExtents(data->font_set, str, nbytes, &overall_ink, &overall_logical);
133 *pwidth = overall_logical.width;
134 *pheight = overall_logical.height;
136 XCharStruct text_structure;
137 int font_direction, font_ascent, font_descent;
138 X11_XTextExtents( data->font_struct, str, nbytes,
139 &font_direction, &font_ascent, &font_descent,
141 *pwidth = text_structure.width;
142 *pheight = text_structure.ascent + text_structure.descent;
148 GetHitButtonIndex( SDL_MessageBoxDataX11 *data,
int x,
int y )
151 int numbuttons = data->numbuttons;
152 SDL_MessageBoxButtonDataX11 *buttonpos = data->buttonpos;
154 for ( i = 0; i < numbuttons; i++ ) {
157 if ( ( x >= rect->
x ) &&
158 ( x <= ( rect->
x + rect->
w ) ) &&
160 ( y <= ( rect->
y + rect->
h ) ) ) {
170 X11_MessageBoxInit( SDL_MessageBoxDataX11 *data,
const SDL_MessageBoxData * messageboxdata,
int * pbuttonid )
177 if ( numbuttons > MAX_BUTTONS ) {
178 return SDL_SetError(
"Too many buttons (%d max allowed)", MAX_BUTTONS);
181 data->dialog_width = MIN_DIALOG_WIDTH;
182 data->dialog_height = MIN_DIALOG_HEIGHT;
183 data->messageboxdata = messageboxdata;
184 data->buttondata = buttondata;
185 data->numbuttons = numbuttons;
186 data->pbuttonid = pbuttonid;
188 data->display = X11_XOpenDisplay(
NULL );
189 if ( !data->display ) {
193 if (SDL_X11_HAVE_UTF8) {
194 char **missing =
NULL;
196 data->font_set = X11_XCreateFontSet(data->display, g_MessageBoxFont,
197 &missing, &num_missing,
NULL);
198 if ( missing !=
NULL ) {
199 X11_XFreeStringList(missing);
201 if ( data->font_set ==
NULL ) {
202 return SDL_SetError(
"Couldn't load font %s", g_MessageBoxFont);
205 data->font_struct = X11_XLoadQueryFont( data->display, g_MessageBoxFontLatin1 );
206 if ( data->font_struct ==
NULL ) {
207 return SDL_SetError(
"Couldn't load font %s", g_MessageBoxFontLatin1);
214 colorhints = g_default_colors;
219 data->color[
i ] = SDL_MAKE_RGB( colorhints[ i ].
r, colorhints[ i ].
g, colorhints[ i ].b );
226 CountLinesOfText(
const char *
text)
229 while (text && *text) {
232 text = lf ? lf + 1 :
NULL;
239 X11_MessageBoxInitPositions( SDL_MessageBoxDataX11 *data )
243 int text_width_max = 0;
244 int button_text_height = 0;
245 int button_width = MIN_BUTTON_WIDTH;
250 const char *text = messageboxdata->
message;
251 const int linecount = CountLinesOfText(text);
252 TextLineData *plinedata = (TextLineData *)
SDL_malloc(
sizeof (TextLineData) * linecount);
258 data->linedata = plinedata;
259 data->numlines = linecount;
261 for ( i = 0; i < linecount; i++, plinedata++ ) {
266 plinedata->text =
text;
268 GetTextWidthHeight( data, text, length, &plinedata->width, &height );
271 data->text_height = IntMax( data->text_height, height );
272 text_width_max = IntMax( text_width_max, plinedata->width );
274 plinedata->length =
length;
275 if (lf && (lf > text) && (lf[-1] ==
'\r')) {
287 data->text_height += 2;
291 for ( i = 0; i < data->numbuttons; i++ ) {
294 data->buttonpos[
i ].buttondata = &data->buttondata[
i ];
295 data->buttonpos[
i ].length =
SDL_strlen( data->buttondata[ i ].text );
297 GetTextWidthHeight( data, data->buttondata[ i ].text,
SDL_strlen( data->buttondata[ i ].text ),
298 &data->buttonpos[ i ].text_width, &height );
300 button_width = IntMax( button_width, data->buttonpos[ i ].text_width );
301 button_text_height = IntMax( button_text_height, height );
304 if ( data->numlines ) {
306 data->xtext = data->text_height;
307 data->ytext = data->text_height + data->text_height;
310 ybuttons = 3 * data->ytext / 2 + ( data->numlines - 1 ) * data->text_height;
313 data->dialog_width = IntMax( data->dialog_width, 2 * data->xtext + text_width_max );
314 data->dialog_height = IntMax( data->dialog_height, ybuttons );
317 ybuttons = button_text_height;
320 if ( data->numbuttons ) {
322 int width_of_buttons;
323 int button_spacing = button_text_height;
324 int button_height = 2 * button_text_height;
327 button_width += button_text_height;
330 width_of_buttons = data->numbuttons * button_width + ( data->numbuttons - 1 ) * button_spacing;
333 data->dialog_width = IntMax( data->dialog_width, width_of_buttons + 2 * button_spacing );
334 data->dialog_height = IntMax( data->dialog_height, ybuttons + 2 * button_height );
337 x = ( data->dialog_width - width_of_buttons ) / 2;
338 y = ybuttons + ( data->dialog_height - ybuttons - button_height ) / 2;
340 for ( i = 0; i < data->numbuttons; i++ ) {
342 data->buttonpos[
i ].rect.x =
x;
343 data->buttonpos[
i ].rect.y =
y;
344 data->buttonpos[
i ].rect.w = button_width;
345 data->buttonpos[
i ].rect.h = button_height;
348 data->buttonpos[
i ].x = x + ( button_width - data->buttonpos[
i ].text_width ) / 2;
349 data->buttonpos[
i ].y = y + ( button_height - button_text_height - 1 ) / 2 + button_text_height;
352 x += button_width + button_spacing;
361 X11_MessageBoxShutdown( SDL_MessageBoxDataX11 *data )
363 if ( data->font_set !=
NULL ) {
364 X11_XFreeFontSet( data->display, data->font_set );
365 data->font_set =
NULL;
368 if ( data->font_struct !=
NULL ) {
369 X11_XFreeFont( data->display, data->font_struct );
370 data->font_struct =
NULL;
373 #if SDL_VIDEO_DRIVER_X11_XDBE 374 if ( SDL_X11_HAVE_XDBE && data->xdbe ) {
375 X11_XdbeDeallocateBackBufferName(data->display, data->buf);
379 if ( data->display ) {
380 if ( data->window != None ) {
381 X11_XWithdrawWindow( data->display, data->window, data->screen );
382 X11_XDestroyWindow( data->display, data->window );
386 X11_XCloseDisplay( data->display );
387 data->display =
NULL;
395 X11_MessageBoxCreateWindow( SDL_MessageBoxDataX11 *data )
398 XSizeHints *sizehints;
399 XSetWindowAttributes wnd_attr;
400 Atom _NET_WM_WINDOW_TYPE, _NET_WM_WINDOW_TYPE_DIALOG, _NET_WM_NAME;
401 Display *display = data->display;
404 char *title_locale =
NULL;
406 if ( messageboxdata->
window ) {
410 data->screen = displaydata->
screen;
412 data->screen = DefaultScreen( display );
415 data->event_mask = ExposureMask |
416 ButtonPressMask | ButtonReleaseMask | KeyPressMask | KeyReleaseMask |
417 StructureNotifyMask | FocusChangeMask | PointerMotionMask;
418 wnd_attr.event_mask = data->event_mask;
420 data->window = X11_XCreateWindow(
421 display, RootWindow(display, data->screen),
423 data->dialog_width, data->dialog_height,
424 0, CopyFromParent, InputOutput, CopyFromParent,
425 CWEventMask, &wnd_attr );
426 if ( data->window == None ) {
432 X11_XSetTransientForHint( display, data->window, windowdata->
xwindow );
435 X11_XStoreName( display, data->window, messageboxdata->
title );
436 _NET_WM_NAME = X11_XInternAtom(display,
"_NET_WM_NAME", False);
440 XTextProperty titleprop;
441 Status status = X11_XStringListToTextProperty(&title_locale, 1, &titleprop);
444 X11_XSetTextProperty(display, data->window, &titleprop, XA_WM_NAME);
445 X11_XFree(titleprop.value);
449 #ifdef X_HAVE_UTF8_STRING 450 if (SDL_X11_HAVE_UTF8) {
451 XTextProperty titleprop;
452 Status status = X11_Xutf8TextListToTextProperty(display, (
char **) &messageboxdata->
title, 1,
453 XUTF8StringStyle, &titleprop);
454 if (status == Success) {
455 X11_XSetTextProperty(display, data->window, &titleprop,
457 X11_XFree(titleprop.value);
463 _NET_WM_WINDOW_TYPE = X11_XInternAtom(display,
"_NET_WM_WINDOW_TYPE", False);
464 _NET_WM_WINDOW_TYPE_DIALOG = X11_XInternAtom(display,
"_NET_WM_WINDOW_TYPE_DIALOG", False);
465 X11_XChangeProperty(display, data->window, _NET_WM_WINDOW_TYPE, XA_ATOM, 32,
467 (
unsigned char *)&_NET_WM_WINDOW_TYPE_DIALOG, 1);
470 data->wm_protocols = X11_XInternAtom( display,
"WM_PROTOCOLS", False );
471 data->wm_delete_message = X11_XInternAtom( display,
"WM_DELETE_WINDOW", False );
472 X11_XSetWMProtocols( display, data->window, &data->wm_delete_message, 1 );
475 XWindowAttributes attrib;
478 X11_XGetWindowAttributes(display, windowdata->
xwindow, &attrib);
479 x = attrib.x + ( attrib.width - data->dialog_width ) / 2;
480 y = attrib.y + ( attrib.height - data->dialog_height ) / 3 ;
481 X11_XTranslateCoordinates(display, windowdata->
xwindow, RootWindow(display, data->screen), x, y, &x, &y, &dummy);
487 x = dpydata->
x + (( dpy->
current_mode.
w - data->dialog_width ) / 2);
488 y = dpydata->
y + (( dpy->
current_mode.
h - data->dialog_height ) / 3);
490 x = ( DisplayWidth( display, data->screen ) - data->dialog_width ) / 2;
491 y = ( DisplayHeight( display, data->screen ) - data->dialog_height ) / 3 ;
494 X11_XMoveWindow( display, data->window, x, y );
496 sizehints = X11_XAllocSizeHints();
498 sizehints->flags = USPosition | USSize | PMaxSize | PMinSize;
501 sizehints->width = data->dialog_width;
502 sizehints->height = data->dialog_height;
504 sizehints->min_width = sizehints->max_width = data->dialog_width;
505 sizehints->min_height = sizehints->max_height = data->dialog_height;
507 X11_XSetWMNormalHints( display, data->window, sizehints );
509 X11_XFree( sizehints );
512 X11_XMapRaised( display, data->window );
514 #if SDL_VIDEO_DRIVER_X11_XDBE 516 if (SDL_X11_HAVE_XDBE) {
517 int xdbe_major, xdbe_minor;
518 if (X11_XdbeQueryExtension(display, &xdbe_major, &xdbe_minor) != 0) {
520 data->buf = X11_XdbeAllocateBackBufferName(display, data->window, XdbeUndefined);
532 X11_MessageBoxDraw( SDL_MessageBoxDataX11 *data, GC
ctx )
535 Drawable
window = data->window;
536 Display *display = data->display;
538 #if SDL_VIDEO_DRIVER_X11_XDBE 539 if (SDL_X11_HAVE_XDBE && data->xdbe) {
541 X11_XdbeBeginIdiom(data->display);
546 X11_XFillRectangle( display, window, ctx, 0, 0, data->dialog_width, data->dialog_height );
549 for ( i = 0; i < data->numlines; i++ ) {
550 TextLineData *plinedata = &data->linedata[
i ];
552 if (SDL_X11_HAVE_UTF8) {
553 X11_Xutf8DrawString( display, window, data->font_set, ctx,
554 data->xtext, data->ytext + i * data->text_height,
555 plinedata->text, plinedata->length );
557 X11_XDrawString( display, window, ctx,
558 data->xtext, data->ytext + i * data->text_height,
559 plinedata->text, plinedata->length );
563 for ( i = 0; i < data->numbuttons; i++ ) {
564 SDL_MessageBoxButtonDataX11 *buttondatax11 = &data->buttonpos[
i ];
567 int offset = ( ( data->mouse_over_index ==
i ) && ( data->button_press_index == data->mouse_over_index ) ) ? 1 : 0;
570 X11_XFillRectangle( display, window, ctx,
571 buttondatax11->rect.x - border, buttondatax11->rect.y - border,
572 buttondatax11->rect.w + 2 * border, buttondatax11->rect.h + 2 * border );
575 X11_XDrawRectangle( display, window, ctx,
576 buttondatax11->rect.x, buttondatax11->rect.y,
577 buttondatax11->rect.w, buttondatax11->rect.h );
579 X11_XSetForeground( display, ctx, ( data->mouse_over_index == i ) ?
583 if (SDL_X11_HAVE_UTF8) {
584 X11_Xutf8DrawString( display, window, data->font_set, ctx,
585 buttondatax11->x + offset,
586 buttondatax11->y + offset,
587 buttondata->
text, buttondatax11->length );
589 X11_XDrawString( display, window, ctx,
590 buttondatax11->x + offset, buttondatax11->y + offset,
591 buttondata->
text, buttondatax11->length );
595 #if SDL_VIDEO_DRIVER_X11_XDBE 596 if (SDL_X11_HAVE_XDBE && data->xdbe) {
597 XdbeSwapInfo swap_info;
598 swap_info.swap_window = data->window;
599 swap_info.swap_action = XdbeUndefined;
600 X11_XdbeSwapBuffers(data->display, &swap_info, 1);
601 X11_XdbeEndIdiom(data->display);
607 X11_MessageBoxEventTest(Display *display, XEvent *
event, XPointer arg)
609 const SDL_MessageBoxDataX11 *data = (
const SDL_MessageBoxDataX11 *) arg;
610 return ((event->xany.display == data->display) && (
event->xany.window == data->window)) ? True : False;
615 X11_MessageBoxLoop( SDL_MessageBoxDataX11 *data )
621 KeySym last_key_pressed = XK_VoidSymbol;
622 unsigned long gcflags = GCForeground | GCBackground;
628 if (!SDL_X11_HAVE_UTF8) {
630 ctx_vals.font = data->font_struct->fid;
633 ctx = X11_XCreateGC( data->display, data->window, gcflags, &ctx_vals );
635 return SDL_SetError(
"Couldn't create graphics context");
638 data->button_press_index = -1;
639 data->mouse_over_index = -1;
641 while( !close_dialog ) {
647 X11_XIfEvent( data->display, &e, X11_MessageBoxEventTest, (XPointer) data );
651 if ( ( e.type != Expose ) && X11_XFilterEvent( &e, None ) )
656 if ( e.xexpose.count > 0 ) {
669 data->button_press_index = -1;
670 data->mouse_over_index = -1;
676 const int previndex = data->mouse_over_index;
677 data->mouse_over_index = GetHitButtonIndex( data, e.xbutton.x, e.xbutton.y );
678 if (data->mouse_over_index == previndex) {
685 if ( e.xclient.message_type == data->wm_protocols &&
686 e.xclient.format == 32 &&
687 e.xclient.data.l[ 0 ] == data->wm_delete_message ) {
694 last_key_pressed = X11_XLookupKeysym( &e.xkey, 0 );
699 KeySym
key = X11_XLookupKeysym( &e.xkey, 0 );
702 if ( key != last_key_pressed )
705 if ( key == XK_Escape )
707 else if ( ( key == XK_Return ) || ( key == XK_KP_Enter ) )
714 for ( i = 0; i < data->numbuttons; i++ ) {
715 SDL_MessageBoxButtonDataX11 *buttondatax11 = &data->buttonpos[
i ];
717 if ( buttondatax11->buttondata->flags & mask ) {
718 *data->pbuttonid = buttondatax11->buttondata->buttonid;
728 data->button_press_index = -1;
729 if ( e.xbutton.button == Button1 ) {
731 data->button_press_index = GetHitButtonIndex( data, e.xbutton.x, e.xbutton.y );
737 if ( ( e.xbutton.button == Button1 ) && ( data->button_press_index >= 0 ) ) {
738 int button = GetHitButtonIndex( data, e.xbutton.x, e.xbutton.y );
740 if ( data->button_press_index == button ) {
741 SDL_MessageBoxButtonDataX11 *buttondatax11 = &data->buttonpos[
button ];
743 *data->pbuttonid = buttondatax11->buttondata->buttonid;
747 data->button_press_index = -1;
753 X11_MessageBoxDraw( data, ctx );
757 X11_XFreeGC( data->display, ctx );
765 SDL_MessageBoxDataX11
data;
776 origlocale = setlocale(LC_ALL,
NULL);
777 if (origlocale !=
NULL) {
779 if (origlocale ==
NULL) {
782 setlocale(LC_ALL,
"");
793 ret = X11_MessageBoxInit( &data, messageboxdata, buttonid );
795 ret = X11_MessageBoxInitPositions( &data );
797 ret = X11_MessageBoxCreateWindow( &data );
799 ret = X11_MessageBoxLoop( &data );
804 X11_MessageBoxShutdown( &data );
808 setlocale(LC_ALL, origlocale);
820 #if SDL_FORK_MESSAGEBOX 826 if (pipe(fds) == -1) {
827 return X11_ShowMessageBoxImpl(messageboxdata, buttonid);
834 return X11_ShowMessageBoxImpl(messageboxdata, buttonid);
835 }
else if (pid == 0) {
838 status = X11_ShowMessageBoxImpl(messageboxdata, buttonid);
839 if (write(fds[1], &status,
sizeof (
int)) !=
sizeof (
int))
841 else if (write(fds[1], buttonid,
sizeof (
int)) !=
sizeof (
int))
849 rc = waitpid(pid, &status, 0);
850 }
while ((rc == -1) && (errno == EINTR));
854 if ((rc == -1) || (!WIFEXITED(status)) || (WEXITSTATUS(status) != 0)) {
858 if (read(fds[0], &status,
sizeof (
int)) !=
sizeof (
int))
860 else if (read(fds[0], buttonid,
sizeof (
int)) !=
sizeof (
int))
867 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.