22 #include "../../SDL_internal.h"
24 #if SDL_VIDEO_DRIVER_X11
31 #include <X11/keysym.h>
35 #define SDL_FORK_MESSAGEBOX 1
36 #define SDL_SET_LOCALE 1
38 #if SDL_FORK_MESSAGEBOX
39 #include <sys/types.h>
46 #define MIN_BUTTON_WIDTH 64
47 #define MIN_DIALOG_WIDTH 200
48 #define MIN_DIALOG_HEIGHT 100
50 static const char g_MessageBoxFontLatin1[] =
"-*-*-medium-r-normal--0-120-*-*-p-0-iso8859-1";
51 static const char g_MessageBoxFont[] =
"-*-*-medium-r-normal--*-120-*-*-*-*-*-*";
61 #define SDL_MAKE_RGB( _r, _g, _b ) ( ( ( Uint32 )( _r ) << 16 ) | \
62 ( ( Uint32 )( _g ) << 8 ) | \
63 ( ( Uint32 )( _b ) ) )
65 typedef struct SDL_MessageBoxButtonDataX11 {
73 } SDL_MessageBoxButtonDataX11;
75 typedef struct TextLineData {
81 typedef struct SDL_MessageBoxDataX11
86 #if SDL_VIDEO_DRIVER_X11_XDBE
92 Atom wm_delete_message;
98 XFontStruct *font_struct;
102 TextLineData *linedata;
106 int button_press_index;
107 int mouse_over_index;
111 SDL_MessageBoxButtonDataX11 buttonpos[ MAX_BUTTONS ];
116 } SDL_MessageBoxDataX11;
120 IntMax(
int a,
int b )
122 return (
a >
b ) ?
a :
b;
127 GetTextWidthHeight( SDL_MessageBoxDataX11 *
data,
const char *str,
int nbytes,
int *pwidth,
int *pheight )
129 if (SDL_X11_HAVE_UTF8) {
130 XRectangle overall_ink, overall_logical;
131 X11_Xutf8TextExtents(
data->font_set, str, nbytes, &overall_ink, &overall_logical);
132 *pwidth = overall_logical.width;
133 *pheight = overall_logical.height;
135 XCharStruct text_structure;
136 int font_direction, font_ascent, font_descent;
137 X11_XTextExtents(
data->font_struct, str, nbytes,
138 &font_direction, &font_ascent, &font_descent,
140 *pwidth = text_structure.width;
141 *pheight = text_structure.ascent + text_structure.descent;
147 GetHitButtonIndex( SDL_MessageBoxDataX11 *
data,
int x,
int y )
150 int numbuttons =
data->numbuttons;
151 SDL_MessageBoxButtonDataX11 *buttonpos =
data->buttonpos;
153 for (
i = 0;
i < numbuttons;
i++ ) {
169 X11_MessageBoxInit( SDL_MessageBoxDataX11 *
data,
const SDL_MessageBoxData * messageboxdata,
int * pbuttonid )
176 if ( numbuttons > MAX_BUTTONS ) {
177 return SDL_SetError(
"Too many buttons (%d max allowed)", MAX_BUTTONS);
180 data->dialog_width = MIN_DIALOG_WIDTH;
181 data->dialog_height = MIN_DIALOG_HEIGHT;
182 data->messageboxdata = messageboxdata;
183 data->buttondata = buttondata;
184 data->numbuttons = numbuttons;
185 data->pbuttonid = pbuttonid;
187 data->display = X11_XOpenDisplay(
NULL );
188 if ( !
data->display ) {
192 if (SDL_X11_HAVE_UTF8) {
193 char **missing =
NULL;
195 data->font_set = X11_XCreateFontSet(
data->display, g_MessageBoxFont,
196 &missing, &num_missing,
NULL);
197 if ( missing !=
NULL ) {
198 X11_XFreeStringList(missing);
201 return SDL_SetError(
"Couldn't load font %s", g_MessageBoxFont);
204 data->font_struct = X11_XLoadQueryFont(
data->display, g_MessageBoxFontLatin1 );
206 return SDL_SetError(
"Couldn't load font %s", g_MessageBoxFontLatin1);
213 colorhints = g_default_colors;
218 data->color[
i ] = SDL_MAKE_RGB( colorhints[
i ].
r, colorhints[
i ].
g, colorhints[
i ].
b );
225 CountLinesOfText(
const char *
text)
238 X11_MessageBoxInitPositions( SDL_MessageBoxDataX11 *
data )
242 int text_width_max = 0;
243 int button_text_height = 0;
244 int button_width = MIN_BUTTON_WIDTH;
248 if ( messageboxdata->
message[0] ) {
250 const int linecount = CountLinesOfText(
text);
251 TextLineData *plinedata = (TextLineData *)
SDL_malloc(
sizeof (TextLineData) * linecount);
257 data->linedata = plinedata;
258 data->numlines = linecount;
260 for (
i = 0;
i < linecount;
i++, plinedata++ ) {
265 plinedata->text =
text;
271 text_width_max = IntMax( text_width_max, plinedata->width );
273 plinedata->length =
length;
274 if (lf && (lf >
text) && (lf[-1] ==
'\r')) {
286 data->text_height += 2;
290 for (
i = 0;
i <
data->numbuttons;
i++ ) {
293 data->buttonpos[
i ].buttondata = &
data->buttondata[
i ];
299 button_width = IntMax( button_width,
data->buttonpos[
i ].text_width );
300 button_text_height = IntMax( button_text_height,
height );
303 if (
data->numlines ) {
309 ybuttons = 3 *
data->ytext / 2 + (
data->numlines - 1 ) *
data->text_height;
312 data->dialog_width = IntMax(
data->dialog_width, 2 *
data->xtext + text_width_max );
313 data->dialog_height = IntMax(
data->dialog_height, ybuttons );
316 ybuttons = button_text_height;
319 if (
data->numbuttons ) {
321 int width_of_buttons;
322 int button_spacing = button_text_height;
323 int button_height = 2 * button_text_height;
326 button_width += button_text_height;
329 width_of_buttons =
data->numbuttons * button_width + (
data->numbuttons - 1 ) * button_spacing;
332 data->dialog_width = IntMax(
data->dialog_width, width_of_buttons + 2 * button_spacing );
333 data->dialog_height = IntMax(
data->dialog_height, ybuttons + 2 * button_height );
337 x =
data->dialog_width - (
data->dialog_width - width_of_buttons ) / 2 - ( button_width + button_spacing );
339 x = (
data->dialog_width - width_of_buttons ) / 2;
341 y = ybuttons + (
data->dialog_height - ybuttons - button_height ) / 2;
343 for (
i = 0;
i <
data->numbuttons;
i++ ) {
345 data->buttonpos[
i ].rect.x =
x;
346 data->buttonpos[
i ].rect.y =
y;
347 data->buttonpos[
i ].rect.w = button_width;
348 data->buttonpos[
i ].rect.h = button_height;
351 data->buttonpos[
i ].x =
x + ( button_width -
data->buttonpos[
i ].text_width ) / 2;
352 data->buttonpos[
i ].y =
y + ( button_height - button_text_height - 1 ) / 2 + button_text_height;
356 x -= button_width + button_spacing;
358 x += button_width + button_spacing;
368 X11_MessageBoxShutdown( SDL_MessageBoxDataX11 *
data )
371 X11_XFreeFontSet(
data->display,
data->font_set );
376 X11_XFreeFont(
data->display,
data->font_struct );
380 #if SDL_VIDEO_DRIVER_X11_XDBE
381 if ( SDL_X11_HAVE_XDBE &&
data->xdbe ) {
382 X11_XdbeDeallocateBackBufferName(
data->display,
data->buf);
386 if (
data->display ) {
387 if (
data->window != None ) {
388 X11_XWithdrawWindow(
data->display,
data->window,
data->screen );
389 X11_XDestroyWindow(
data->display,
data->window );
393 X11_XCloseDisplay(
data->display );
402 X11_MessageBoxCreateWindow( SDL_MessageBoxDataX11 *
data )
405 XSizeHints *sizehints;
406 XSetWindowAttributes wnd_attr;
407 Atom _NET_WM_WINDOW_TYPE, _NET_WM_WINDOW_TYPE_DIALOG, _NET_WM_NAME;
408 Display *display =
data->display;
411 char *title_locale =
NULL;
413 if ( messageboxdata->
window ) {
419 data->screen = DefaultScreen( display );
422 data->event_mask = ExposureMask |
423 ButtonPressMask | ButtonReleaseMask | KeyPressMask | KeyReleaseMask |
424 StructureNotifyMask | FocusChangeMask | PointerMotionMask;
425 wnd_attr.event_mask =
data->event_mask;
427 data->window = X11_XCreateWindow(
428 display, RootWindow(display,
data->screen),
430 data->dialog_width,
data->dialog_height,
431 0, CopyFromParent, InputOutput, CopyFromParent,
432 CWEventMask, &wnd_attr );
433 if (
data->window == None ) {
438 Atom _NET_WM_STATE = X11_XInternAtom(display,
"_NET_WM_STATE", False);
440 size_t statecount = 0;
443 stateatoms[statecount++] = X11_XInternAtom(display,
"_NET_WM_STATE_SKIP_TASKBAR", False);
444 stateatoms[statecount++] = X11_XInternAtom(display,
"_NET_WM_STATE_SKIP_PAGER", False);
445 stateatoms[statecount++] = X11_XInternAtom(display,
"_NET_WM_STATE_FOCUSED", False);
446 stateatoms[statecount++] = X11_XInternAtom(display,
"_NET_WM_STATE_MODAL", False);
448 X11_XChangeProperty(display,
data->window, _NET_WM_STATE, XA_ATOM, 32,
449 PropModeReplace, (
unsigned char *)stateatoms, statecount);
452 X11_XSetTransientForHint( display,
data->window, windowdata->
xwindow );
455 X11_XStoreName( display,
data->window, messageboxdata->
title );
456 _NET_WM_NAME = X11_XInternAtom(display,
"_NET_WM_NAME", False);
460 XTextProperty titleprop;
461 Status status = X11_XStringListToTextProperty(&title_locale, 1, &titleprop);
464 X11_XSetTextProperty(display,
data->window, &titleprop, XA_WM_NAME);
465 X11_XFree(titleprop.value);
469 #ifdef X_HAVE_UTF8_STRING
470 if (SDL_X11_HAVE_UTF8) {
471 XTextProperty titleprop;
472 Status status = X11_Xutf8TextListToTextProperty(display, (
char **) &messageboxdata->
title, 1,
473 XUTF8StringStyle, &titleprop);
474 if (status == Success) {
475 X11_XSetTextProperty(display,
data->window, &titleprop,
477 X11_XFree(titleprop.value);
483 _NET_WM_WINDOW_TYPE = X11_XInternAtom(display,
"_NET_WM_WINDOW_TYPE", False);
484 _NET_WM_WINDOW_TYPE_DIALOG = X11_XInternAtom(display,
"_NET_WM_WINDOW_TYPE_DIALOG", False);
485 X11_XChangeProperty(display,
data->window, _NET_WM_WINDOW_TYPE, XA_ATOM, 32,
487 (
unsigned char *)&_NET_WM_WINDOW_TYPE_DIALOG, 1);
490 data->wm_protocols = X11_XInternAtom( display,
"WM_PROTOCOLS", False );
491 data->wm_delete_message = X11_XInternAtom( display,
"WM_DELETE_WINDOW", False );
492 X11_XSetWMProtocols( display,
data->window, &
data->wm_delete_message, 1 );
495 XWindowAttributes attrib;
498 X11_XGetWindowAttributes(display, windowdata->
xwindow, &attrib);
499 x = attrib.x + ( attrib.width -
data->dialog_width ) / 2;
500 y = attrib.y + ( attrib.height -
data->dialog_height ) / 3 ;
501 X11_XTranslateCoordinates(display, windowdata->
xwindow, RootWindow(display,
data->screen),
x,
y, &
x, &
y, &dummy);
507 x = dpydata->
x + ((
dpy->current_mode.w -
data->dialog_width ) / 2);
508 y = dpydata->
y + ((
dpy->current_mode.h -
data->dialog_height ) / 3);
510 x = ( DisplayWidth( display,
data->screen ) -
data->dialog_width ) / 2;
511 y = ( DisplayHeight( display,
data->screen ) -
data->dialog_height ) / 3 ;
514 X11_XMoveWindow( display,
data->window,
x,
y );
516 sizehints = X11_XAllocSizeHints();
518 sizehints->flags = USPosition | USSize | PMaxSize | PMinSize;
521 sizehints->width =
data->dialog_width;
522 sizehints->height =
data->dialog_height;
524 sizehints->min_width = sizehints->max_width =
data->dialog_width;
525 sizehints->min_height = sizehints->max_height =
data->dialog_height;
527 X11_XSetWMNormalHints( display,
data->window, sizehints );
529 X11_XFree( sizehints );
532 X11_XMapRaised( display,
data->window );
534 #if SDL_VIDEO_DRIVER_X11_XDBE
536 if (SDL_X11_HAVE_XDBE) {
537 int xdbe_major, xdbe_minor;
538 if (X11_XdbeQueryExtension(display, &xdbe_major, &xdbe_minor) != 0) {
540 data->buf = X11_XdbeAllocateBackBufferName(display,
data->window, XdbeUndefined);
552 X11_MessageBoxDraw( SDL_MessageBoxDataX11 *
data, GC
ctx )
556 Display *display =
data->display;
558 #if SDL_VIDEO_DRIVER_X11_XDBE
559 if (SDL_X11_HAVE_XDBE &&
data->xdbe) {
561 X11_XdbeBeginIdiom(
data->display);
566 X11_XFillRectangle( display,
window,
ctx, 0, 0,
data->dialog_width,
data->dialog_height );
569 for (
i = 0;
i <
data->numlines;
i++ ) {
570 TextLineData *plinedata = &
data->linedata[
i ];
572 if (SDL_X11_HAVE_UTF8) {
575 plinedata->text, plinedata->length );
579 plinedata->text, plinedata->length );
583 for (
i = 0;
i <
data->numbuttons;
i++ ) {
584 SDL_MessageBoxButtonDataX11 *buttondatax11 = &
data->buttonpos[
i ];
587 int offset = ( (
data->mouse_over_index ==
i ) && (
data->button_press_index ==
data->mouse_over_index ) ) ? 1 : 0;
590 X11_XFillRectangle( display,
window,
ctx,
591 buttondatax11->rect.x -
border, buttondatax11->rect.y -
border,
592 buttondatax11->rect.w + 2 *
border, buttondatax11->rect.h + 2 *
border );
595 X11_XDrawRectangle( display,
window,
ctx,
596 buttondatax11->rect.x, buttondatax11->rect.y,
597 buttondatax11->rect.w, buttondatax11->rect.h );
599 X11_XSetForeground( display,
ctx, (
data->mouse_over_index ==
i ) ?
603 if (SDL_X11_HAVE_UTF8) {
605 buttondatax11->x +
offset,
606 buttondatax11->y +
offset,
607 buttondata->
text, buttondatax11->length );
611 buttondata->
text, buttondatax11->length );
615 #if SDL_VIDEO_DRIVER_X11_XDBE
616 if (SDL_X11_HAVE_XDBE &&
data->xdbe) {
617 XdbeSwapInfo swap_info;
618 swap_info.swap_window =
data->window;
619 swap_info.swap_action = XdbeUndefined;
620 X11_XdbeSwapBuffers(
data->display, &swap_info, 1);
621 X11_XdbeEndIdiom(
data->display);
627 X11_MessageBoxEventTest(Display *display, XEvent *
event, XPointer arg)
629 const SDL_MessageBoxDataX11 *
data = (
const SDL_MessageBoxDataX11 *) arg;
630 return ((
event->xany.display ==
data->display) && (
event->xany.window ==
data->window)) ? True : False;
635 X11_MessageBoxLoop( SDL_MessageBoxDataX11 *
data )
641 KeySym last_key_pressed = XK_VoidSymbol;
642 unsigned long gcflags = GCForeground | GCBackground;
648 if (!SDL_X11_HAVE_UTF8) {
650 ctx_vals.font =
data->font_struct->fid;
653 ctx = X11_XCreateGC(
data->display,
data->window, gcflags, &ctx_vals );
655 return SDL_SetError(
"Couldn't create graphics context");
658 data->button_press_index = -1;
659 data->mouse_over_index = -1;
661 while( !close_dialog ) {
667 X11_XIfEvent(
data->display, &
e, X11_MessageBoxEventTest, (XPointer)
data );
671 if ( (
e.type != Expose ) && X11_XFilterEvent( &
e, None ) )
676 if (
e.xexpose.count > 0 ) {
689 data->button_press_index = -1;
690 data->mouse_over_index = -1;
696 const int previndex =
data->mouse_over_index;
697 data->mouse_over_index = GetHitButtonIndex(
data,
e.xbutton.x,
e.xbutton.y );
698 if (
data->mouse_over_index == previndex) {
705 if (
e.xclient.message_type ==
data->wm_protocols &&
706 e.xclient.format == 32 &&
707 e.xclient.data.l[ 0 ] ==
data->wm_delete_message ) {
714 last_key_pressed = X11_XLookupKeysym( &
e.xkey, 0 );
719 KeySym
key = X11_XLookupKeysym( &
e.xkey, 0 );
722 if (
key != last_key_pressed )
725 if (
key == XK_Escape )
727 else if ( (
key == XK_Return ) || (
key == XK_KP_Enter ) )
734 for (
i = 0;
i <
data->numbuttons;
i++ ) {
735 SDL_MessageBoxButtonDataX11 *buttondatax11 = &
data->buttonpos[
i ];
737 if ( buttondatax11->buttondata->flags &
mask ) {
738 *
data->pbuttonid = buttondatax11->buttondata->buttonid;
748 data->button_press_index = -1;
749 if (
e.xbutton.button == Button1 ) {
751 data->button_press_index = GetHitButtonIndex(
data,
e.xbutton.x,
e.xbutton.y );
757 if ( (
e.xbutton.button == Button1 ) && (
data->button_press_index >= 0 ) ) {
758 int button = GetHitButtonIndex(
data,
e.xbutton.x,
e.xbutton.y );
761 SDL_MessageBoxButtonDataX11 *buttondatax11 = &
data->buttonpos[
button ];
763 *
data->pbuttonid = buttondatax11->buttondata->buttonid;
767 data->button_press_index = -1;
773 X11_MessageBoxDraw(
data,
ctx );
777 X11_XFreeGC(
data->display,
ctx );
785 SDL_MessageBoxDataX11
data;
796 origlocale = setlocale(LC_ALL,
NULL);
797 if (origlocale !=
NULL) {
799 if (origlocale ==
NULL) {
802 setlocale(LC_ALL,
"");
813 ret = X11_MessageBoxInit( &
data, messageboxdata, buttonid );
815 ret = X11_MessageBoxInitPositions( &
data );
817 ret = X11_MessageBoxCreateWindow( &
data );
819 ret = X11_MessageBoxLoop( &
data );
824 X11_MessageBoxShutdown( &
data );
828 setlocale(LC_ALL, origlocale);
840 #if SDL_FORK_MESSAGEBOX
846 if (pipe(
fds) == -1) {
847 return X11_ShowMessageBoxImpl(messageboxdata, buttonid);
854 return X11_ShowMessageBoxImpl(messageboxdata, buttonid);
855 }
else if (pid == 0) {
858 status = X11_ShowMessageBoxImpl(messageboxdata, buttonid);
859 if (write(
fds[1], &status,
sizeof (
int)) !=
sizeof (
int))
861 else if (write(
fds[1], buttonid,
sizeof (
int)) !=
sizeof (
int))
869 rc = waitpid(pid, &status, 0);
870 }
while ((rc == -1) && (errno == EINTR));
874 if ((rc == -1) || (!WIFEXITED(status)) || (WEXITSTATUS(status) != 0)) {
878 if (read(
fds[0], &status,
sizeof (
int)) !=
sizeof (
int))
880 else if (read(
fds[0], buttonid,
sizeof (
int)) !=
sizeof (
int))
887 return X11_ShowMessageBoxImpl(messageboxdata, buttonid);
#define SDL_assert(condition)
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
#define SDL_OutOfMemory()
@ SDL_MESSAGEBOX_COLOR_MAX
@ SDL_MESSAGEBOX_COLOR_BUTTON_BACKGROUND
@ SDL_MESSAGEBOX_COLOR_BUTTON_SELECTED
@ SDL_MESSAGEBOX_COLOR_BACKGROUND
@ SDL_MESSAGEBOX_COLOR_TEXT
@ SDL_MESSAGEBOX_COLOR_BUTTON_BORDER
@ SDL_MESSAGEBOX_BUTTONS_RIGHT_TO_LEFT
@ SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT
@ SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT
GLint GLint GLint GLint GLint GLint y
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
GLint GLint GLsizei GLsizei GLsizei GLint border
GLint GLint GLsizei width
GLdouble GLdouble GLdouble r
GLint GLint GLint GLint GLint x
GLint GLint GLsizei GLsizei height
GLboolean GLboolean GLboolean b
GLboolean GLboolean GLboolean GLboolean a
GLenum GLuint GLenum GLsizei const GLchar * buf
GLuint GLsizei GLsizei * length
#define SDL_arraysize(array)
#define SDL_iconv_utf8_locale(S)
SDL_VideoDevice * SDL_GetVideoDevice(void)
SDL_VideoDisplay * SDL_GetDisplayForWindow(SDL_Window *window)
int SDL_X11_LoadSymbols(void)
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)
return Display return Display Bool Bool int int int return Display XEvent Bool(*) XPointer return Display return Display dpy)
EGLSurface EGLNativeWindowType * window
RGB value used in a message box color scheme.
SDL_MessageBoxColor colors[SDL_MESSAGEBOX_COLOR_MAX]
MessageBox structure containing title, text, window, etc.
const SDL_MessageBoxColorScheme * colorScheme
const SDL_MessageBoxButtonData * buttons
A rectangle, with the origin at the upper left (integer).
SDL_VideoDisplay * displays
static char text[MAX_TEXT_LENGTH]