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 MAX_TEXT_LINES 32 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[] =
"-*-*-*-*-*-*-*-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[ MAX_TEXT_LINES ];
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 );
227 X11_MessageBoxInitPositions( SDL_MessageBoxDataX11 *data )
231 int text_width_max = 0;
232 int button_text_height = 0;
233 int button_width = MIN_BUTTON_WIDTH;
239 TextLineData *plinedata = data->linedata;
241 for ( i = 0; i < MAX_TEXT_LINES; i++, plinedata++ ) {
243 char *lf =
SDL_strchr( (
char * )text,
'\n' );
248 plinedata->length = ( lf && ( i < MAX_TEXT_LINES - 1 ) ) ? ( lf -
text ) :
SDL_strlen( text );
249 plinedata->text =
text;
251 GetTextWidthHeight( data, text, plinedata->length, &plinedata->width, &height );
254 data->text_height = IntMax( data->text_height, height );
255 text_width_max = IntMax( text_width_max, plinedata->width );
257 if (lf && (lf > text) && (lf[-1] ==
'\r')) {
261 text += plinedata->length + 1;
269 data->text_height += 2;
273 for ( i = 0; i < data->numbuttons; i++ ) {
276 data->buttonpos[
i ].buttondata = &data->buttondata[
i ];
277 data->buttonpos[
i ].length =
SDL_strlen( data->buttondata[ i ].text );
279 GetTextWidthHeight( data, data->buttondata[ i ].text,
SDL_strlen( data->buttondata[ i ].text ),
280 &data->buttonpos[ i ].text_width, &height );
282 button_width = IntMax( button_width, data->buttonpos[ i ].text_width );
283 button_text_height = IntMax( button_text_height, height );
286 if ( data->numlines ) {
288 data->xtext = data->text_height;
289 data->ytext = data->text_height + data->text_height;
292 ybuttons = 3 * data->ytext / 2 + ( data->numlines - 1 ) * data->text_height;
295 data->dialog_width = IntMax( data->dialog_width, 2 * data->xtext + text_width_max );
296 data->dialog_height = IntMax( data->dialog_height, ybuttons );
299 ybuttons = button_text_height;
302 if ( data->numbuttons ) {
304 int width_of_buttons;
305 int button_spacing = button_text_height;
306 int button_height = 2 * button_text_height;
309 button_width += button_text_height;
312 width_of_buttons = data->numbuttons * button_width + ( data->numbuttons - 1 ) * button_spacing;
315 data->dialog_width = IntMax( data->dialog_width, width_of_buttons + 2 * button_spacing );
316 data->dialog_height = IntMax( data->dialog_height, ybuttons + 2 * button_height );
319 x = ( data->dialog_width - width_of_buttons ) / 2;
320 y = ybuttons + ( data->dialog_height - ybuttons - button_height ) / 2;
322 for ( i = 0; i < data->numbuttons; i++ ) {
324 data->buttonpos[
i ].rect.x =
x;
325 data->buttonpos[
i ].rect.y =
y;
326 data->buttonpos[
i ].rect.w = button_width;
327 data->buttonpos[
i ].rect.h = button_height;
330 data->buttonpos[
i ].x = x + ( button_width - data->buttonpos[
i ].text_width ) / 2;
331 data->buttonpos[
i ].y = y + ( button_height - button_text_height - 1 ) / 2 + button_text_height;
334 x += button_width + button_spacing;
343 X11_MessageBoxShutdown( SDL_MessageBoxDataX11 *data )
345 if ( data->font_set !=
NULL ) {
346 X11_XFreeFontSet( data->display, data->font_set );
347 data->font_set =
NULL;
350 if ( data->font_struct !=
NULL ) {
351 X11_XFreeFont( data->display, data->font_struct );
352 data->font_struct =
NULL;
355 #if SDL_VIDEO_DRIVER_X11_XDBE 356 if ( SDL_X11_HAVE_XDBE && data->xdbe ) {
357 X11_XdbeDeallocateBackBufferName(data->display, data->buf);
361 if ( data->display ) {
362 if ( data->window != None ) {
363 X11_XWithdrawWindow( data->display, data->window, data->screen );
364 X11_XDestroyWindow( data->display, data->window );
368 X11_XCloseDisplay( data->display );
369 data->display =
NULL;
375 X11_MessageBoxCreateWindow( SDL_MessageBoxDataX11 *data )
378 XSizeHints *sizehints;
379 XSetWindowAttributes wnd_attr;
380 Atom _NET_WM_WINDOW_TYPE, _NET_WM_WINDOW_TYPE_DIALOG, _NET_WM_NAME, UTF8_STRING;
381 Display *display = data->display;
385 if ( messageboxdata->
window ) {
389 data->screen = displaydata->
screen;
391 data->screen = DefaultScreen( display );
394 data->event_mask = ExposureMask |
395 ButtonPressMask | ButtonReleaseMask | KeyPressMask | KeyReleaseMask |
396 StructureNotifyMask | FocusChangeMask | PointerMotionMask;
397 wnd_attr.event_mask = data->event_mask;
399 data->window = X11_XCreateWindow(
400 display, RootWindow(display, data->screen),
402 data->dialog_width, data->dialog_height,
403 0, CopyFromParent, InputOutput, CopyFromParent,
404 CWEventMask, &wnd_attr );
405 if ( data->window == None ) {
411 X11_XSetTransientForHint( display, data->window, windowdata->
xwindow );
414 X11_XStoreName( display, data->window, messageboxdata->
title );
415 _NET_WM_NAME = X11_XInternAtom(display,
"_NET_WM_NAME", False);
416 UTF8_STRING = X11_XInternAtom(display,
"UTF8_STRING", False);
417 X11_XChangeProperty(display, data->window, _NET_WM_NAME, UTF8_STRING, 8,
418 PropModeReplace, (
unsigned char *) messageboxdata->
title,
419 strlen(messageboxdata->
title) + 1 );
422 _NET_WM_WINDOW_TYPE = X11_XInternAtom(display,
"_NET_WM_WINDOW_TYPE", False);
423 _NET_WM_WINDOW_TYPE_DIALOG = X11_XInternAtom(display,
"_NET_WM_WINDOW_TYPE_DIALOG", False);
424 X11_XChangeProperty(display, data->window, _NET_WM_WINDOW_TYPE, XA_ATOM, 32,
426 (
unsigned char *)&_NET_WM_WINDOW_TYPE_DIALOG, 1);
429 data->wm_protocols = X11_XInternAtom( display,
"WM_PROTOCOLS", False );
430 data->wm_delete_message = X11_XInternAtom( display,
"WM_DELETE_WINDOW", False );
431 X11_XSetWMProtocols( display, data->window, &data->wm_delete_message, 1 );
434 XWindowAttributes attrib;
437 X11_XGetWindowAttributes(display, windowdata->
xwindow, &attrib);
438 x = attrib.x + ( attrib.width - data->dialog_width ) / 2;
439 y = attrib.y + ( attrib.height - data->dialog_height ) / 3 ;
440 X11_XTranslateCoordinates(display, windowdata->
xwindow, RootWindow(display, data->screen), x, y, &x, &y, &dummy);
446 x = dpydata->
x + (( dpy->
current_mode.
w - data->dialog_width ) / 2);
447 y = dpydata->
y + (( dpy->
current_mode.
h - data->dialog_height ) / 3);
449 x = ( DisplayWidth( display, data->screen ) - data->dialog_width ) / 2;
450 y = ( DisplayHeight( display, data->screen ) - data->dialog_height ) / 3 ;
453 X11_XMoveWindow( display, data->window, x, y );
455 sizehints = X11_XAllocSizeHints();
457 sizehints->flags = USPosition | USSize | PMaxSize | PMinSize;
460 sizehints->width = data->dialog_width;
461 sizehints->height = data->dialog_height;
463 sizehints->min_width = sizehints->max_width = data->dialog_width;
464 sizehints->min_height = sizehints->max_height = data->dialog_height;
466 X11_XSetWMNormalHints( display, data->window, sizehints );
468 X11_XFree( sizehints );
471 X11_XMapRaised( display, data->window );
473 #if SDL_VIDEO_DRIVER_X11_XDBE 475 if (SDL_X11_HAVE_XDBE) {
476 int xdbe_major, xdbe_minor;
477 if (X11_XdbeQueryExtension(display, &xdbe_major, &xdbe_minor) != 0) {
479 data->buf = X11_XdbeAllocateBackBufferName(display, data->window, XdbeUndefined);
491 X11_MessageBoxDraw( SDL_MessageBoxDataX11 *data, GC ctx )
494 Drawable
window = data->window;
495 Display *display = data->display;
497 #if SDL_VIDEO_DRIVER_X11_XDBE 498 if (SDL_X11_HAVE_XDBE && data->xdbe) {
500 X11_XdbeBeginIdiom(data->display);
505 X11_XFillRectangle( display, window, ctx, 0, 0, data->dialog_width, data->dialog_height );
508 for ( i = 0; i < data->numlines; i++ ) {
509 TextLineData *plinedata = &data->linedata[
i ];
511 if (SDL_X11_HAVE_UTF8) {
512 X11_Xutf8DrawString( display, window, data->font_set, ctx,
513 data->xtext, data->ytext + i * data->text_height,
514 plinedata->text, plinedata->length );
516 X11_XDrawString( display, window, ctx,
517 data->xtext, data->ytext + i * data->text_height,
518 plinedata->text, plinedata->length );
522 for ( i = 0; i < data->numbuttons; i++ ) {
523 SDL_MessageBoxButtonDataX11 *buttondatax11 = &data->buttonpos[
i ];
526 int offset = ( ( data->mouse_over_index ==
i ) && ( data->button_press_index == data->mouse_over_index ) ) ? 1 : 0;
529 X11_XFillRectangle( display, window, ctx,
530 buttondatax11->rect.x - border, buttondatax11->rect.y - border,
531 buttondatax11->rect.w + 2 * border, buttondatax11->rect.h + 2 * border );
534 X11_XDrawRectangle( display, window, ctx,
535 buttondatax11->rect.x, buttondatax11->rect.y,
536 buttondatax11->rect.w, buttondatax11->rect.h );
538 X11_XSetForeground( display, ctx, ( data->mouse_over_index == i ) ?
542 if (SDL_X11_HAVE_UTF8) {
543 X11_Xutf8DrawString( display, window, data->font_set, ctx,
544 buttondatax11->x + offset,
545 buttondatax11->y + offset,
546 buttondata->
text, buttondatax11->length );
548 X11_XDrawString( display, window, ctx,
549 buttondatax11->x + offset, buttondatax11->y + offset,
550 buttondata->
text, buttondatax11->length );
554 #if SDL_VIDEO_DRIVER_X11_XDBE 555 if (SDL_X11_HAVE_XDBE && data->xdbe) {
556 XdbeSwapInfo swap_info;
557 swap_info.swap_window = data->window;
558 swap_info.swap_action = XdbeUndefined;
559 X11_XdbeSwapBuffers(data->display, &swap_info, 1);
560 X11_XdbeEndIdiom(data->display);
566 X11_MessageBoxEventTest(Display *display, XEvent *
event, XPointer arg)
568 const SDL_MessageBoxDataX11 *data = (
const SDL_MessageBoxDataX11 *) arg;
569 return ((event->xany.display == data->display) && (
event->xany.window == data->window)) ? True : False;
574 X11_MessageBoxLoop( SDL_MessageBoxDataX11 *data )
580 KeySym last_key_pressed = XK_VoidSymbol;
581 unsigned long gcflags = GCForeground | GCBackground;
587 if (!SDL_X11_HAVE_UTF8) {
589 ctx_vals.font = data->font_struct->fid;
592 ctx = X11_XCreateGC( data->display, data->window, gcflags, &ctx_vals );
594 return SDL_SetError(
"Couldn't create graphics context");
597 data->button_press_index = -1;
598 data->mouse_over_index = -1;
600 while( !close_dialog ) {
606 X11_XIfEvent( data->display, &e, X11_MessageBoxEventTest, (XPointer) data );
610 if ( ( e.type != Expose ) && X11_XFilterEvent( &e, None ) )
615 if ( e.xexpose.count > 0 ) {
628 data->button_press_index = -1;
629 data->mouse_over_index = -1;
635 const int previndex = data->mouse_over_index;
636 data->mouse_over_index = GetHitButtonIndex( data, e.xbutton.x, e.xbutton.y );
637 if (data->mouse_over_index == previndex) {
644 if ( e.xclient.message_type == data->wm_protocols &&
645 e.xclient.format == 32 &&
646 e.xclient.data.l[ 0 ] == data->wm_delete_message ) {
653 last_key_pressed = X11_XLookupKeysym( &e.xkey, 0 );
658 KeySym key = X11_XLookupKeysym( &e.xkey, 0 );
661 if ( key != last_key_pressed )
664 if ( key == XK_Escape )
666 else if ( ( key == XK_Return ) || ( key == XK_KP_Enter ) )
673 for ( i = 0; i < data->numbuttons; i++ ) {
674 SDL_MessageBoxButtonDataX11 *buttondatax11 = &data->buttonpos[
i ];
676 if ( buttondatax11->buttondata->flags & mask ) {
677 *data->pbuttonid = buttondatax11->buttondata->buttonid;
687 data->button_press_index = -1;
688 if ( e.xbutton.button == Button1 ) {
690 data->button_press_index = GetHitButtonIndex( data, e.xbutton.x, e.xbutton.y );
696 if ( ( e.xbutton.button == Button1 ) && ( data->button_press_index >= 0 ) ) {
697 int button = GetHitButtonIndex( data, e.xbutton.x, e.xbutton.y );
699 if ( data->button_press_index == button ) {
700 SDL_MessageBoxButtonDataX11 *buttondatax11 = &data->buttonpos[
button ];
702 *data->pbuttonid = buttondatax11->buttondata->buttonid;
706 data->button_press_index = -1;
712 X11_MessageBoxDraw( data, ctx );
716 X11_XFreeGC( data->display, ctx );
724 SDL_MessageBoxDataX11
data;
735 origlocale = setlocale(LC_ALL,
NULL);
736 if (origlocale !=
NULL) {
738 if (origlocale ==
NULL) {
741 setlocale(LC_ALL,
"");
752 ret = X11_MessageBoxInit( &data, messageboxdata, buttonid );
754 ret = X11_MessageBoxInitPositions( &data );
756 ret = X11_MessageBoxCreateWindow( &data );
758 ret = X11_MessageBoxLoop( &data );
763 X11_MessageBoxShutdown( &data );
767 setlocale(LC_ALL, origlocale);
779 #if SDL_FORK_MESSAGEBOX 785 if (pipe(fds) == -1) {
786 return X11_ShowMessageBoxImpl(messageboxdata, buttonid);
793 return X11_ShowMessageBoxImpl(messageboxdata, buttonid);
794 }
else if (pid == 0) {
797 status = X11_ShowMessageBoxImpl(messageboxdata, buttonid);
798 if (write(fds[1], &status,
sizeof (
int)) !=
sizeof (
int))
800 else if (write(fds[1], buttonid,
sizeof (
int)) !=
sizeof (
int))
808 rc = waitpid(pid, &status, 0);
809 }
while ((rc == -1) && (errno == EINTR));
813 if ((rc == -1) || (!WIFEXITED(status)) || (WEXITSTATUS(status) != 0)) {
817 if (read(fds[0], &status,
sizeof (
int)) !=
sizeof (
int))
819 else if (read(fds[0], buttonid,
sizeof (
int)) !=
sizeof (
int))
826 return X11_ShowMessageBoxImpl(messageboxdata, buttonid);
GLdouble GLdouble GLdouble r
uint32_t Uint32
An unsigned 32-bit integer type.
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
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
GLint GLint GLint GLint GLint x
RGB value used in a message box color scheme.
GLint GLint GLsizei GLsizei height
int SDL_X11_LoadSymbols(void)
SDL_DisplayMode current_mode
SDL_VideoDisplay * displays
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 GLint GLint GLint GLint y
SDL_VideoDisplay * SDL_GetDisplayForWindow(SDL_Window *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.