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++ ) {
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);
202 return SDL_SetError(
"Couldn't load font %s", g_MessageBoxFont);
205 data->font_struct = X11_XLoadQueryFont(
data->display, g_MessageBoxFontLatin1 );
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)
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;
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;
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 ];
300 button_width = IntMax( button_width,
data->buttonpos[
i ].text_width );
301 button_text_height = IntMax( button_text_height,
height );
304 if (
data->numlines ) {
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 )
364 X11_XFreeFontSet(
data->display,
data->font_set );
369 X11_XFreeFont(
data->display,
data->font_struct );
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 );
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 ) {
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 ) {
431 Atom _NET_WM_STATE = X11_XInternAtom(display,
"_NET_WM_STATE", False);
433 size_t statecount = 0;
436 stateatoms[statecount++] = X11_XInternAtom(display,
"_NET_WM_STATE_SKIP_TASKBAR", False);
437 stateatoms[statecount++] = X11_XInternAtom(display,
"_NET_WM_STATE_SKIP_PAGER", False);
438 stateatoms[statecount++] = X11_XInternAtom(display,
"_NET_WM_STATE_FOCUSED", False);
439 stateatoms[statecount++] = X11_XInternAtom(display,
"_NET_WM_STATE_MODAL", False);
441 X11_XChangeProperty(display,
data->window, _NET_WM_STATE, XA_ATOM, 32,
442 PropModeReplace, (
unsigned char *)stateatoms, statecount);
445 X11_XSetTransientForHint( display,
data->window, windowdata->
xwindow );
448 X11_XStoreName( display,
data->window, messageboxdata->
title );
449 _NET_WM_NAME = X11_XInternAtom(display,
"_NET_WM_NAME", False);
453 XTextProperty titleprop;
454 Status status = X11_XStringListToTextProperty(&title_locale, 1, &titleprop);
457 X11_XSetTextProperty(display,
data->window, &titleprop, XA_WM_NAME);
458 X11_XFree(titleprop.value);
462 #ifdef X_HAVE_UTF8_STRING
463 if (SDL_X11_HAVE_UTF8) {
464 XTextProperty titleprop;
465 Status status = X11_Xutf8TextListToTextProperty(display, (
char **) &messageboxdata->
title, 1,
466 XUTF8StringStyle, &titleprop);
467 if (status == Success) {
468 X11_XSetTextProperty(display,
data->window, &titleprop,
470 X11_XFree(titleprop.value);
476 _NET_WM_WINDOW_TYPE = X11_XInternAtom(display,
"_NET_WM_WINDOW_TYPE", False);
477 _NET_WM_WINDOW_TYPE_DIALOG = X11_XInternAtom(display,
"_NET_WM_WINDOW_TYPE_DIALOG", False);
478 X11_XChangeProperty(display,
data->window, _NET_WM_WINDOW_TYPE, XA_ATOM, 32,
480 (
unsigned char *)&_NET_WM_WINDOW_TYPE_DIALOG, 1);
483 data->wm_protocols = X11_XInternAtom( display,
"WM_PROTOCOLS", False );
484 data->wm_delete_message = X11_XInternAtom( display,
"WM_DELETE_WINDOW", False );
485 X11_XSetWMProtocols( display,
data->window, &
data->wm_delete_message, 1 );
488 XWindowAttributes attrib;
491 X11_XGetWindowAttributes(display, windowdata->
xwindow, &attrib);
492 x = attrib.x + ( attrib.width -
data->dialog_width ) / 2;
493 y = attrib.y + ( attrib.height -
data->dialog_height ) / 3 ;
494 X11_XTranslateCoordinates(display, windowdata->
xwindow, RootWindow(display,
data->screen),
x,
y, &
x, &
y, &dummy);
500 x = dpydata->
x + ((
dpy->current_mode.w -
data->dialog_width ) / 2);
501 y = dpydata->
y + ((
dpy->current_mode.h -
data->dialog_height ) / 3);
503 x = ( DisplayWidth( display,
data->screen ) -
data->dialog_width ) / 2;
504 y = ( DisplayHeight( display,
data->screen ) -
data->dialog_height ) / 3 ;
507 X11_XMoveWindow( display,
data->window,
x,
y );
509 sizehints = X11_XAllocSizeHints();
511 sizehints->flags = USPosition | USSize | PMaxSize | PMinSize;
514 sizehints->width =
data->dialog_width;
515 sizehints->height =
data->dialog_height;
517 sizehints->min_width = sizehints->max_width =
data->dialog_width;
518 sizehints->min_height = sizehints->max_height =
data->dialog_height;
520 X11_XSetWMNormalHints( display,
data->window, sizehints );
522 X11_XFree( sizehints );
525 X11_XMapRaised( display,
data->window );
527 #if SDL_VIDEO_DRIVER_X11_XDBE
529 if (SDL_X11_HAVE_XDBE) {
530 int xdbe_major, xdbe_minor;
531 if (X11_XdbeQueryExtension(display, &xdbe_major, &xdbe_minor) != 0) {
533 data->buf = X11_XdbeAllocateBackBufferName(display,
data->window, XdbeUndefined);
545 X11_MessageBoxDraw( SDL_MessageBoxDataX11 *
data, GC
ctx )
549 Display *display =
data->display;
551 #if SDL_VIDEO_DRIVER_X11_XDBE
552 if (SDL_X11_HAVE_XDBE &&
data->xdbe) {
554 X11_XdbeBeginIdiom(
data->display);
559 X11_XFillRectangle( display,
window,
ctx, 0, 0,
data->dialog_width,
data->dialog_height );
562 for (
i = 0;
i <
data->numlines;
i++ ) {
563 TextLineData *plinedata = &
data->linedata[
i ];
565 if (SDL_X11_HAVE_UTF8) {
568 plinedata->text, plinedata->length );
572 plinedata->text, plinedata->length );
576 for (
i = 0;
i <
data->numbuttons;
i++ ) {
577 SDL_MessageBoxButtonDataX11 *buttondatax11 = &
data->buttonpos[
i ];
580 int offset = ( (
data->mouse_over_index ==
i ) && (
data->button_press_index ==
data->mouse_over_index ) ) ? 1 : 0;
583 X11_XFillRectangle( display,
window,
ctx,
584 buttondatax11->rect.x -
border, buttondatax11->rect.y -
border,
585 buttondatax11->rect.w + 2 *
border, buttondatax11->rect.h + 2 *
border );
588 X11_XDrawRectangle( display,
window,
ctx,
589 buttondatax11->rect.x, buttondatax11->rect.y,
590 buttondatax11->rect.w, buttondatax11->rect.h );
592 X11_XSetForeground( display,
ctx, (
data->mouse_over_index ==
i ) ?
596 if (SDL_X11_HAVE_UTF8) {
598 buttondatax11->x +
offset,
599 buttondatax11->y +
offset,
600 buttondata->
text, buttondatax11->length );
604 buttondata->
text, buttondatax11->length );
608 #if SDL_VIDEO_DRIVER_X11_XDBE
609 if (SDL_X11_HAVE_XDBE &&
data->xdbe) {
610 XdbeSwapInfo swap_info;
611 swap_info.swap_window =
data->window;
612 swap_info.swap_action = XdbeUndefined;
613 X11_XdbeSwapBuffers(
data->display, &swap_info, 1);
614 X11_XdbeEndIdiom(
data->display);
620 X11_MessageBoxEventTest(Display *display, XEvent *
event, XPointer arg)
622 const SDL_MessageBoxDataX11 *
data = (
const SDL_MessageBoxDataX11 *) arg;
623 return ((
event->xany.display ==
data->display) && (
event->xany.window ==
data->window)) ? True : False;
628 X11_MessageBoxLoop( SDL_MessageBoxDataX11 *
data )
634 KeySym last_key_pressed = XK_VoidSymbol;
635 unsigned long gcflags = GCForeground | GCBackground;
641 if (!SDL_X11_HAVE_UTF8) {
643 ctx_vals.font =
data->font_struct->fid;
646 ctx = X11_XCreateGC(
data->display,
data->window, gcflags, &ctx_vals );
648 return SDL_SetError(
"Couldn't create graphics context");
651 data->button_press_index = -1;
652 data->mouse_over_index = -1;
654 while( !close_dialog ) {
660 X11_XIfEvent(
data->display, &
e, X11_MessageBoxEventTest, (XPointer)
data );
664 if ( (
e.type != Expose ) && X11_XFilterEvent( &
e, None ) )
669 if (
e.xexpose.count > 0 ) {
682 data->button_press_index = -1;
683 data->mouse_over_index = -1;
689 const int previndex =
data->mouse_over_index;
690 data->mouse_over_index = GetHitButtonIndex(
data,
e.xbutton.x,
e.xbutton.y );
691 if (
data->mouse_over_index == previndex) {
698 if (
e.xclient.message_type ==
data->wm_protocols &&
699 e.xclient.format == 32 &&
700 e.xclient.data.l[ 0 ] ==
data->wm_delete_message ) {
707 last_key_pressed = X11_XLookupKeysym( &
e.xkey, 0 );
712 KeySym
key = X11_XLookupKeysym( &
e.xkey, 0 );
715 if (
key != last_key_pressed )
718 if (
key == XK_Escape )
720 else if ( (
key == XK_Return ) || (
key == XK_KP_Enter ) )
727 for (
i = 0;
i <
data->numbuttons;
i++ ) {
728 SDL_MessageBoxButtonDataX11 *buttondatax11 = &
data->buttonpos[
i ];
730 if ( buttondatax11->buttondata->flags &
mask ) {
731 *
data->pbuttonid = buttondatax11->buttondata->buttonid;
741 data->button_press_index = -1;
742 if (
e.xbutton.button == Button1 ) {
744 data->button_press_index = GetHitButtonIndex(
data,
e.xbutton.x,
e.xbutton.y );
750 if ( (
e.xbutton.button == Button1 ) && (
data->button_press_index >= 0 ) ) {
751 int button = GetHitButtonIndex(
data,
e.xbutton.x,
e.xbutton.y );
754 SDL_MessageBoxButtonDataX11 *buttondatax11 = &
data->buttonpos[
button ];
756 *
data->pbuttonid = buttondatax11->buttondata->buttonid;
760 data->button_press_index = -1;
766 X11_MessageBoxDraw(
data,
ctx );
770 X11_XFreeGC(
data->display,
ctx );
778 SDL_MessageBoxDataX11
data;
789 origlocale = setlocale(LC_ALL,
NULL);
790 if (origlocale !=
NULL) {
792 if (origlocale ==
NULL) {
795 setlocale(LC_ALL,
"");
806 ret = X11_MessageBoxInit( &
data, messageboxdata, buttonid );
808 ret = X11_MessageBoxInitPositions( &
data );
810 ret = X11_MessageBoxCreateWindow( &
data );
812 ret = X11_MessageBoxLoop( &
data );
817 X11_MessageBoxShutdown( &
data );
821 setlocale(LC_ALL, origlocale);
833 #if SDL_FORK_MESSAGEBOX
839 if (pipe(
fds) == -1) {
840 return X11_ShowMessageBoxImpl(messageboxdata, buttonid);
847 return X11_ShowMessageBoxImpl(messageboxdata, buttonid);
848 }
else if (pid == 0) {
851 status = X11_ShowMessageBoxImpl(messageboxdata, buttonid);
852 if (write(
fds[1], &status,
sizeof (
int)) !=
sizeof (
int))
854 else if (write(
fds[1], buttonid,
sizeof (
int)) !=
sizeof (
int))
862 rc = waitpid(pid, &status, 0);
863 }
while ((rc == -1) && (errno == EINTR));
867 if ((rc == -1) || (!WIFEXITED(status)) || (WEXITSTATUS(status) != 0)) {
871 if (read(
fds[0], &status,
sizeof (
int)) !=
sizeof (
int))
873 else if (read(
fds[0], buttonid,
sizeof (
int)) !=
sizeof (
int))
880 return X11_ShowMessageBoxImpl(messageboxdata, buttonid);