Atlas - SDL_x11toolkit.c
Home / ext / SDL / src / video / x11 Lines: 3 | Size: 102638 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)][FILE BEGIN]1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2026 Sam Lantinga <[email protected]> 4 5 This software is provided 'as-is', without any express or implied 6 warranty. In no event will the authors be held liable for any damages 7 arising from the use of this software. 8 9 Permission is granted to anyone to use this software for any purpose, 10 including commercial applications, and to alter it and redistribute it 11 freely, subject to the following restrictions: 12 13 1. The origin of this software must not be misrepresented; you must not 14 claim that you wrote the original software. If you use this software 15 in a product, an acknowledgment in the product documentation would be 16 appreciated but is not required. 17 2. Altered source versions must be plainly marked as such, and must not be 18 misrepresented as being the original software. 19 3. This notice may not be removed or altered from any source distribution. 20*/ 21 22#include "SDL_internal.h" 23 24#ifdef SDL_VIDEO_DRIVER_X11 25 26#include "../../SDL_list.h" 27#include "SDL_x11video.h" 28#ifdef SDL_USE_LIBDBUS 29#include "../../core/linux/SDL_system_theme.h" 30#endif 31#ifdef HAVE_FRIBIDI_H 32#include "../../core/unix/SDL_fribidi.h" 33#endif 34#include "SDL_x11dyn.h" 35#include "SDL_x11toolkit.h" 36#include "SDL_x11settings.h" 37#include "SDL_x11modes.h" 38#include "xsettings-client.h" 39#include <X11/keysym.h> 40#include <locale.h> 41 42#define SDL_SET_LOCALE 1 43#define SDL_GRAB 1 44 45typedef enum SDL_ToolkitTextTypeX11 46{ 47 SDL_TOOLKIT_TEXT_TYPE_X11_GENERIC, 48 SDL_TOOLKIT_TEXT_TYPE_X11_THAI 49} SDL_ToolkitTextTypeX11; 50 51#ifdef HAVE_LIBTHAI_H 52typedef struct SDL_ToolkitThaiOverlayX11 53{ 54 bool top; 55 char *str; 56 size_t sz; 57 SDL_Rect rect; 58} SDL_ToolkitThaiOverlayX11; 59#endif 60 61typedef struct SDL_ToolkitTextElementX11 62{ 63 SDL_ToolkitTextTypeX11 type; 64 char *str; 65 size_t sz; 66 SDL_Rect rect; 67 int font_h; 68 void (*str_free)(void *); 69#ifdef HAVE_LIBTHAI_H 70 SDL_ListNode *thai_overlays; 71#endif 72} SDL_ToolkitTextElementX11; 73 74typedef struct SDL_ToolkitIconControlX11 75{ 76 SDL_ToolkitControlX11 parent; 77 78 /* Icon type */ 79 SDL_MessageBoxFlags flags; 80 char icon_char; 81 82 /* Font */ 83 XFontStruct *icon_char_font; 84 int icon_char_x; 85 int icon_char_y; 86 int icon_char_a; 87 int icon_char_h; 88 89 /* Colors */ 90 XColor xcolor_black; 91 XColor xcolor_red; 92 XColor xcolor_red_darker; 93 XColor xcolor_white; 94 XColor xcolor_yellow; 95 XColor xcolor_blue; 96 XColor xcolor_bg_shadow; 97} SDL_ToolkitIconControlX11; 98 99typedef struct SDL_ToolkitButtonControlX11 100{ 101 SDL_ToolkitControlX11 parent; 102 103 /* Data */ 104 const SDL_MessageBoxButtonData *data; 105 106 /* Text */ 107 SDL_ListNode *text; 108 SDL_Rect text_rect; 109 110 /* Callback */ 111 void *cb_data; 112 void (*cb)(struct SDL_ToolkitControlX11 *, void *); 113} SDL_ToolkitButtonControlX11; 114 115typedef struct SDL_ToolkitLabelControlLineX11 116{ 117 SDL_ListNode *text; 118 SDL_Rect rect; 119#ifdef HAVE_FRIBIDI_H 120 FriBidiParType par; 121#endif 122} SDL_ToolkitLabelControlLineX11; 123 124typedef struct SDL_ToolkitLabelControlX11 125{ 126 SDL_ToolkitControlX11 parent; 127 128 /* char **lines; 129 int *y; 130 size_t *szs; 131 size_t sz; 132#ifdef HAVE_FRIBIDI_H 133 int *x; 134 int *w; 135 bool *free_lines; 136 FriBidiParType *par_types; 137#endif*/ 138 SDL_ToolkitLabelControlLineX11 *lines; 139 size_t sz; 140} SDL_ToolkitLabelControlX11; 141 142typedef struct SDL_ToolkitMenuBarControlX11 143{ 144 SDL_ToolkitControlX11 parent; 145 146 SDL_ListNode *menu_items; 147} SDL_ToolkitMenuBarControlX11; 148 149typedef struct SDL_ToolkitMenuControlX11 150{ 151 SDL_ToolkitControlX11 parent; 152 153 SDL_ListNode *menu_items; 154 XColor xcolor_check_bg; 155} SDL_ToolkitMenuControlX11; 156 157/* Font for icon control */ 158static const char *g_IconFont = "-*-*-bold-r-normal-*-%d-*-*-*-*-*-iso8859-1[33 88 105]"; 159#define G_ICONFONT_SIZE 22 160 161/* General UI font */ 162static const char g_ToolkitFontLatin1[] = 163 "-*-*-medium-r-normal--0-%d-*-*-p-0-iso8859-1"; 164static const char g_ToolkitFontLatin1Fallback[] = 165 "-*-*-*-*-*--*-*-*-*-*-*-iso8859-1"; 166 167static const char *g_ToolkitFont[] = { 168 "-*-*-medium-r-normal--*-%d-*-*-*-*-iso10646-1,*", // explicitly unicode (iso10646-1) 169 "-*-*-medium-r-*--*-%d-*-*-*-*-iso10646-1,*", // explicitly unicode (iso10646-1) 170 "-misc-*-*-*-*--*-*-*-*-*-*-iso10646-1,*", // misc unicode (fix for some systems) 171 "-*-*-*-*-*--*-*-*-*-*-*-iso10646-1,*", // just give me anything Unicode. 172 "-*-*-medium-r-normal--*-%d-*-*-*-*-iso8859-1,*", // explicitly latin1, in case low-ASCII works out. 173 "-*-*-medium-r-*--*-%d-*-*-*-*-iso8859-1,*", // explicitly latin1, in case low-ASCII works out. 174 "-misc-*-*-*-*--*-*-*-*-*-*-iso8859-1,*", // misc latin1 (fix for some systems) 175 "-*-*-*-*-*--*-*-*-*-*-*-iso8859-1,*", // just give me anything latin1. 176 NULL 177}; 178#define G_TOOLKITFONT_SIZE 140 179 180static const SDL_MessageBoxColor g_default_colors[SDL_MESSAGEBOX_COLOR_COUNT] = { 181 { 191, 184, 191 }, // SDL_MESSAGEBOX_COLOR_BACKGROUND, 182 { 0, 0, 0 }, // SDL_MESSAGEBOX_COLOR_TEXT, 183 { 127, 120, 127 }, // SDL_MESSAGEBOX_COLOR_BUTTON_BORDER, 184 { 191, 184, 191 }, // SDL_MESSAGEBOX_COLOR_BUTTON_BACKGROUND, 185 { 235, 235, 235 }, // SDL_MESSAGEBOX_COLOR_BUTTON_SELECTED, 186}; 187 188#ifdef SDL_USE_LIBDBUS 189static const SDL_MessageBoxColor g_default_colors_dark[SDL_MESSAGEBOX_COLOR_COUNT] = { 190 { 20, 20, 20 }, // SDL_MESSAGEBOX_COLOR_BACKGROUND, 191 { 192, 192, 192 }, // SDL_MESSAGEBOX_COLOR_TEXT, 192 { 12, 12, 12 }, // SDL_MESSAGEBOX_COLOR_BUTTON_BORDER, 193 { 20, 20, 20 }, // SDL_MESSAGEBOX_COLOR_BUTTON_BACKGROUND, 194 { 36, 36, 36 }, // SDL_MESSAGEBOX_COLOR_BUTTON_SELECTED, 195}; 196 197#if 0 198static const SDL_MessageBoxColor g_default_colors_dark_high_contrast[SDL_MESSAGEBOX_COLOR_COUNT] = { 199 { 0, 0, 0 }, // SDL_MESSAGEBOX_COLOR_BACKGROUND, 200 { 255, 255, 255 }, // SDL_MESSAGEBOX_COLOR_TEXT, 201 { 20, 235, 255 }, // SDL_MESSAGEBOX_COLOR_BUTTON_BORDER, 202 { 0, 0, 0 }, // SDL_MESSAGEBOX_COLOR_BUTTON_BACKGROUND, 203 { 125, 5, 125 }, // SDL_MESSAGEBOX_COLOR_BUTTON_SELECTED, 204}; 205 206static const SDL_MessageBoxColor g_default_colors_light_high_contrast[SDL_MESSAGEBOX_COLOR_COUNT] = { 207 { 255, 255, 255 }, // SDL_MESSAGEBOX_COLOR_BACKGROUND, 208 { 0, 0, 0 }, // SDL_MESSAGEBOX_COLOR_TEXT, 209 { 0, 0, 0 }, // SDL_MESSAGEBOX_COLOR_BUTTON_BORDER, 210 { 255, 255, 255 }, // SDL_MESSAGEBOX_COLOR_BUTTON_BACKGROUND, 211 { 20, 230, 255 }, // SDL_MESSAGEBOX_COLOR_BUTTON_SELECTED, 212}; 213#endif 214 215#endif 216 217static int g_shm_error; 218static int (*g_old_error_handler)(Display *, XErrorEvent *) = NULL; 219 220static int X11Toolkit_SharedMemoryErrorHandler(Display *d, XErrorEvent *e) 221{ 222 if (e->error_code == BadAccess || e->error_code == BadRequest) { 223 g_shm_error = True; 224 return 0; 225 } 226 return g_old_error_handler(d, e); 227} 228 229static void X11Toolkit_InitWindowPixmap(SDL_ToolkitWindowX11 *data) { 230 if (data->pixmap) { 231#ifndef NO_SHARED_MEMORY 232 if (!data->shm_pixmap) { 233 data->drawable = X11_XCreatePixmap(data->display, data->window, data->pixmap_width, data->pixmap_height, data->depth); 234 } 235#else 236 data->drawable = X11_XCreatePixmap(data->display, data->window, data->pixmap_width, data->pixmap_height, data->depth); 237#endif 238#ifndef NO_SHARED_MEMORY 239 if (data->shm) { 240 data->image = X11_XShmCreateImage(data->display, data->visual, data->depth, ZPixmap, NULL, &data->shm_info, data->pixmap_width, data->pixmap_height); 241 if (data->image) { 242 data->shm_bytes_per_line = data->image->bytes_per_line; 243 244 data->shm_info.shmid = shmget(IPC_PRIVATE, data->image->bytes_per_line * data->image->height, IPC_CREAT | 0777); 245 if (data->shm_info.shmid < 0) { 246 XDestroyImage(data->image); 247 data->image = NULL; 248 data->shm = false; 249 return; 250 } 251 252 data->shm_info.readOnly = False; 253 data->shm_info.shmaddr = data->image->data = (char *)shmat(data->shm_info.shmid, NULL, 0); 254 if (((signed char *)data->shm_info.shmaddr) == (signed char *)-1) { 255 XDestroyImage(data->image); 256 data->shm = false; 257 data->image = NULL; 258 return; 259 } 260 261 g_shm_error = False; 262 g_old_error_handler = X11_XSetErrorHandler(X11Toolkit_SharedMemoryErrorHandler); 263 X11_XShmAttach(data->display, &data->shm_info); 264 X11_XSync(data->display, False); 265 X11_XSetErrorHandler(g_old_error_handler); 266 if (g_shm_error) { 267 XDestroyImage(data->image); 268 shmdt(data->shm_info.shmaddr); 269 shmctl(data->shm_info.shmid, IPC_RMID, NULL); 270 data->image = NULL; 271 data->shm = false; 272 return; 273 } 274 275 if (data->shm_pixmap) { 276 data->drawable = X11_XShmCreatePixmap(data->display, data->window, data->shm_info.shmaddr, &data->shm_info, data->pixmap_width, data->pixmap_height, data->depth); 277 if (data->drawable == None) { 278 data->shm_pixmap = False; 279 } else { 280 XDestroyImage(data->image); 281 data->image = NULL; 282 } 283 } 284 285 shmctl(data->shm_info.shmid, IPC_RMID, NULL); 286 } else { 287 data->shm = false; 288 } 289 } 290#endif 291 } 292} 293 294static void X11Toolkit_InitWindowFonts(SDL_ToolkitWindowX11 *window) 295{ 296 window->thai_encoding = SDL_TOOLKIT_THAI_ENCODING_X11_NONE; 297 window->thai_font = SDL_TOOLKIT_THAI_FONT_X11_CELL; 298#ifdef X_HAVE_UTF8_STRING 299 window->utf8 = true; 300 window->font_set = NULL; 301 if (SDL_X11_HAVE_UTF8) { 302 char **missing = NULL; 303 int num_missing = 0; 304 int i_font; 305 window->font_struct = NULL; 306 for (i_font = 0; g_ToolkitFont[i_font]; ++i_font) { 307 char *font; 308 309 if (SDL_strstr(g_ToolkitFont[i_font], "%d")) { 310 try_load_font: 311 SDL_asprintf(&font, g_ToolkitFont[i_font], G_TOOLKITFONT_SIZE * window->iscale); 312 window->font_set = X11_XCreateFontSet(window->display, font, &missing, &num_missing, NULL); 313 SDL_free(font); 314 315 if (!window->font_set) { 316 if (window->scale != 0 && window->iscale > 0) { 317 window->iscale = (int)SDL_ceilf(window->scale); 318 window->scale = 0; 319 } else { 320 window->iscale--; 321 } 322 goto try_load_font; 323 } 324 } else { 325 window->font_set = X11_XCreateFontSet(window->display, g_ToolkitFont[i_font], &missing, &num_missing, NULL); 326 } 327 328 if (missing) { 329 X11_XFreeStringList(missing); 330 } 331 332 if (window->font_set) { 333 break; 334 } 335 } 336 337 if (!window->font_set) { 338 goto load_font_traditional; 339 } else { 340 XFontStruct **font_structs; 341 char **font_names; 342 int font_sz; 343 int i; 344 345#ifdef HAVE_FRIBIDI_H 346 window->do_shaping = !X11_XContextDependentDrawing(window->font_set); 347#endif 348 /* TODO: What to do the XFontSet happens to have more than one Thai font? */ 349 font_sz = X11_XFontsOfFontSet(window->font_set, &font_structs, &font_names); 350 for (i = 0; i < font_sz; i++) { 351 SDL_ToolkitThaiEncodingX11 thai_encoding; 352 353 thai_encoding = SDL_TOOLKIT_THAI_ENCODING_X11_NONE; 354 if (SDL_strstr(font_names[i], "tis620-0")) { 355 thai_encoding = SDL_TOOLKIT_THAI_ENCODING_X11_TIS; 356 } else if (SDL_strstr(font_names[i], "tis620-1")) { 357 thai_encoding = SDL_TOOLKIT_THAI_ENCODING_X11_TIS_MAC; 358 } else if (SDL_strstr(font_names[i], "tis620-2")) { 359 thai_encoding = SDL_TOOLKIT_THAI_ENCODING_X11_TIS_WIN; 360 } else if (SDL_strstr(font_names[i], "iso8859-11")) { 361 thai_encoding = SDL_TOOLKIT_THAI_ENCODING_X11_8859; 362 } else if (SDL_strstr(font_names[i], "iso10646-1")) { 363 thai_encoding = SDL_TOOLKIT_THAI_ENCODING_X11_UNICODE; 364 } 365 366 /* TODO: Set encoding to none if the font does not actually have any Thai codepoints */ 367 if (thai_encoding != SDL_TOOLKIT_THAI_ENCODING_X11_NONE) { 368 XFontStruct *font_struct; 369 370 /* We have to load the font again because the font_struct supplied by FontsOfFontSet does not have the per_char member set */ 371 font_struct = X11_XLoadQueryFont(window->display, font_names[i]); 372 if (font_struct) { 373 if (font_struct->per_char) { 374 int glyphs_sz; 375 int j; 376 377 glyphs_sz = (font_struct->max_char_or_byte2 - font_struct->min_char_or_byte2 + 1) * (font_struct->max_byte1 - font_struct->min_byte1 + 1); 378 for (j = 0; j < glyphs_sz; j++) { 379 if (font_struct->per_char[j].lbearing < 0) { 380 window->thai_font = SDL_TOOLKIT_THAI_FONT_X11_OFFSET; 381 } 382 } 383 } 384 X11_XFreeFont(window->display, font_struct); 385 } 386 } 387 388 window->thai_encoding = thai_encoding; 389 } 390 } 391 } else 392#endif 393 { 394 char *font; 395 396 load_font_traditional: 397 window->utf8 = false; 398 SDL_asprintf(&font, g_ToolkitFontLatin1, G_TOOLKITFONT_SIZE * window->iscale); 399 window->font_struct = X11_XLoadQueryFont(window->display, font); 400 SDL_free(font); 401 if (!window->font_struct) { 402 if (window->iscale > 0) { 403 if (window->scale != 0) { 404 window->iscale = (int)SDL_ceilf(window->scale); 405 window->scale = 0; 406 } else { 407 window->iscale--; 408 } 409 goto load_font_traditional; 410 } else { 411 window->font_struct = X11_XLoadQueryFont(window->display, g_ToolkitFontLatin1Fallback); 412 } 413 } 414 } 415} 416 417static void X11Toolkit_SettingsNotify(const char *name, XSettingsAction action, XSettingsSetting *setting, void *data) 418{ 419 SDL_ToolkitWindowX11 *window; 420 int i; 421 422 window = data; 423 424 if (window->xsettings_first_time) { 425 return; 426 } 427 428 if (SDL_strcmp(name, SDL_XSETTINGS_GDK_WINDOW_SCALING_FACTOR) == 0 || 429 SDL_strcmp(name, SDL_XSETTINGS_GDK_UNSCALED_DPI) == 0 || 430 SDL_strcmp(name, SDL_XSETTINGS_XFT_DPI) == 0) { 431 bool dbe_already_setup = false; 432 bool pixmap_already_setup = false; 433 434 if (window->pixmap) { 435 pixmap_already_setup = true; 436 } else { 437 dbe_already_setup = true; 438 } 439 440 /* set scale vars */ 441 window->scale = X11_GetGlobalContentScale(window->display, window->xsettings); 442 window->iscale = (int)SDL_ceilf(window->scale); 443 if (window->scale < 1) { 444 window->scale = 1; 445 } 446 if (SDL_roundf(window->scale) == window->scale) { 447 window->scale = 0; 448 } 449 450 /* setup fonts */ 451#ifdef X_HAVE_UTF8_STRING 452 if (window->font_set) { 453 X11_XFreeFontSet(window->display, window->font_set); 454 } 455#endif 456 if (window->font_struct) { 457 X11_XFreeFont(window->display, window->font_struct); 458 } 459 460 X11Toolkit_InitWindowFonts(window); 461 462 /* set up window */ 463 if (window->scale != 0) { 464 window->window_width = SDL_lroundf((window->window_width/window->iscale) * window->scale); 465 window->window_height = SDL_lroundf((window->window_height/window->iscale) * window->scale); 466 window->pixmap_width = window->window_width; 467 window->pixmap_height = window->window_height; 468 window->pixmap = true; 469 } else { 470 window->pixmap = false; 471 } 472 473 if (window->pixmap) { 474 if (!pixmap_already_setup) { 475#ifdef SDL_VIDEO_DRIVER_X11_XDBE 476 if (SDL_X11_HAVE_XDBE && window->xdbe) { 477 X11_XdbeDeallocateBackBufferName(window->display, window->buf); 478 } 479#endif 480 } 481 X11_XFreePixmap(window->display, window->drawable); 482 X11Toolkit_InitWindowPixmap(window); 483 } else { 484 if (!dbe_already_setup) { 485 X11_XFreePixmap(window->display, window->drawable); 486#ifndef NO_SHARED_MEMORY 487 if (window->image) { 488 XDestroyImage(window->image); 489 window->image = NULL; 490 } 491#endif 492#ifdef SDL_VIDEO_DRIVER_X11_XDBE 493 if (SDL_X11_HAVE_XDBE && window->xdbe) { 494 window->buf = X11_XdbeAllocateBackBufferName(window->display, window->window, XdbeUndefined); 495 window->drawable = window->buf; 496 } 497#endif 498 } 499 } 500 501 /* notify controls */ 502 for (i = 0; i < window->controls_sz; i++) { 503 window->controls[i]->do_size = true; 504 505 if (window->controls[i]->func_on_scale_change) { 506 window->controls[i]->func_on_scale_change(window->controls[i]); 507 } 508 509 if (window->controls[i]->func_calc_size) { 510 window->controls[i]->func_calc_size(window->controls[i]); 511 } 512 513 window->controls[i]->do_size = false; 514 } 515 516 /* notify cb */ 517 if (window->cb_on_scale_change) { 518 window->cb_on_scale_change(window, window->cb_data); 519 } 520 521 /* update ev scales */ 522 if (!window->pixmap) { 523 window->ev_scale = window->ev_iscale = 1; 524 } else { 525 window->ev_scale = window->scale; 526 window->ev_iscale = window->iscale; 527 } 528 } 529} 530 531static void X11Toolkit_GetTextWidthHeightForFont(XFontStruct *font, const char *str, int nbytes, int *pwidth, int *pheight, int *ascent, int *font_height) 532{ 533 XCharStruct text_structure; 534 int font_direction, font_ascent, font_descent; 535 536 X11_XTextExtents(font, str, nbytes, &font_direction, &font_ascent, &font_descent, &text_structure); 537 *pwidth = text_structure.width; 538 *pheight = text_structure.ascent + text_structure.descent; 539 *ascent = text_structure.ascent; 540 if (font_height) { 541 *font_height = font_ascent + font_descent; 542 } 543} 544 545static void X11Toolkit_GetTextWidthHeight(SDL_ToolkitWindowX11 *data, const char *str, int nbytes, int *pwidth, int *pheight, int *ascent, int *descent, int *font_height) 546{ 547#ifdef X_HAVE_UTF8_STRING 548 if (data->utf8) { 549 XRectangle overall_ink, overall_logical; 550 551 X11_Xutf8TextExtents(data->font_set, str, nbytes, &overall_ink, &overall_logical); 552 *pwidth = overall_logical.width; 553 *pheight = overall_logical.height; 554 *ascent = -overall_logical.y; 555 *descent = overall_logical.height - *ascent; 556 557 if (font_height) { 558 XFontSetExtents *extents; 559 560 extents = X11_XExtentsOfFontSet(data->font_set); 561 *font_height = extents->max_logical_extent.height; 562 } 563 } else 564#endif 565 { 566 XCharStruct text_structure; 567 int font_direction, font_ascent, font_descent; 568 X11_XTextExtents(data->font_struct, str, nbytes, 569 &font_direction, &font_ascent, &font_descent, 570 &text_structure); 571 *pwidth = text_structure.width; 572 *pheight = text_structure.ascent + text_structure.descent; 573 *ascent = text_structure.ascent; 574 *descent = text_structure.descent; 575 576 if (font_height) { 577 *font_height = font_ascent + font_descent; 578 } 579 } 580} 581 582#ifdef HAVE_FRIBIDI_H 583SDL_ListNode *X11Toolkit_MakeTextElements(SDL_ToolkitWindowX11 *data, char *txt, size_t sz, FriBidiParType *par) 584#else 585SDL_ListNode *X11Toolkit_MakeTextElements(SDL_ToolkitWindowX11 *data, char *txt, size_t sz) 586#endif 587{ 588 SDL_ListNode *list; 589 char *str; 590 char *buffer; 591 Uint32 cp; 592 bool thai; 593 bool free_txt; 594 595 free_txt = false; 596 list = NULL; 597 thai = 0; 598 str = txt; 599 buffer = SDL_malloc(1); 600 buffer[0] = 0; 601 602#ifdef HAVE_FRIBIDI_H 603 if (par) { 604 *par = FRIBIDI_PAR_LTR; 605 } 606 if (data->fribidi) { 607 char *fstr; 608 609 fstr = SDL_FriBidi_Process(data->fribidi, str, sz, data->do_shaping, par); 610 if (fstr) { 611 txt = fstr; 612 str = fstr; 613 sz = SDL_strlen(str); 614 free_txt = true; 615 } 616 } 617#endif 618 619 while (1) { 620 char *new; 621 char utf8[5]; 622 size_t csz; 623 bool cond; 624 625 SDL_zeroa(utf8); 626 cp = SDL_StepUTF8((const char **)&str, &sz); 627 cond = (0xe00 <= cp && cp <= 0xe7f) ? true : false; 628 if (cp == 0 || cond == (thai ? false : true)) { 629 SDL_ToolkitTextElementX11 *element; 630 631 element = SDL_malloc(sizeof(SDL_ToolkitTextElementX11)); 632 if (thai) { 633 element->type = SDL_TOOLKIT_TEXT_TYPE_X11_THAI; 634 } else { 635 element->type = SDL_TOOLKIT_TEXT_TYPE_X11_GENERIC; 636 } 637 element->str = SDL_strdup(buffer); 638 element->sz = SDL_strlen(buffer); 639 element->str_free = SDL_free; 640 641 SDL_ListAdd(&list, element); 642 643 SDL_free(buffer); 644 buffer = SDL_malloc(1); 645 buffer[0] = 0; 646 thai = thai ? false : true; 647 } 648 649 if (!cp) { 650 break; 651 } 652 653 SDL_UCS4ToUTF8(cp, utf8); 654 csz = SDL_strlen(buffer) + SDL_strlen(utf8) + 1; 655 new = SDL_malloc(csz); 656 SDL_strlcpy(new, buffer, csz); 657 SDL_strlcat(new, utf8, csz); 658 SDL_free(buffer); 659 buffer = new; 660 } 661 662 SDL_free(buffer); 663 if (free_txt) { 664 SDL_free(txt); 665 } 666 return list; 667} 668 669void X11Toolkit_ShapeTextElements(SDL_ToolkitWindowX11 *data, SDL_ListNode *list) 670{ 671 SDL_ListNode *cursor; 672 SDL_ToolkitTextElementX11 *prev; 673 int temp; 674 675 /* Shape and calculate bounding box */ 676 cursor = list; 677 while (cursor) { 678 SDL_ToolkitTextElementX11 *element; 679 680 element = cursor->entry; 681#ifdef HAVE_LIBTHAI_H 682 element->thai_overlays = NULL; 683#endif 684 if (element->type == SDL_TOOLKIT_TEXT_TYPE_X11_THAI) { 685 if (data->thai_font == SDL_TOOLKIT_THAI_FONT_X11_OFFSET) { 686 X11Toolkit_GetTextWidthHeight(data, element->str, element->sz, &element->rect.w, &element->rect.h, &element->rect.y, &temp, NULL); 687 } else { 688#ifdef HAVE_LIBTHAI_H 689 if (data->th) { 690 struct thcell_t *cells; 691 char *tis_str; 692 char *base_tis_str; 693 size_t cells_sz; 694 size_t base_tis_str_sz; 695 size_t tis_str_sz; 696 697 tis_str = SDL_iconv_string("TIS-620", "UTF-8", element->str, element->sz); 698 cells_sz = tis_str_sz = SDL_strlen(tis_str); 699 700 cells = SDL_calloc(cells_sz, sizeof(struct thcell_t)); 701 data->th->make_cells((const thchar_t *)tis_str, tis_str_sz, cells, &cells_sz, 0); 702 703 base_tis_str_sz = cells_sz; 704 base_tis_str = SDL_malloc(base_tis_str_sz + 1); 705 for (temp = 0; temp < cells_sz; temp++) { 706 base_tis_str[temp] = cells[temp].base; 707 708 if (cells[temp].hilo) { 709 SDL_ToolkitThaiOverlayX11 *overlay; 710 char *pre; 711 int temp2; 712 713 overlay = SDL_malloc(sizeof(SDL_ToolkitThaiOverlayX11)); 714 pre = SDL_iconv_string("UTF-8", "TIS-620", base_tis_str, temp); 715 overlay->str = SDL_iconv_string("UTF-8", "TIS-620", (const char *)&cells[temp].hilo, 1); 716 overlay->sz = SDL_strlen(overlay->str); 717 overlay->top = false; 718 X11Toolkit_GetTextWidthHeight(data, pre, SDL_strlen(pre), &overlay->rect.x, &temp2, &temp2, &temp2, NULL); 719 X11Toolkit_GetTextWidthHeight(data, overlay->str, overlay->sz, &overlay->rect.w, &overlay->rect.h, &overlay->rect.y, &temp2, NULL); 720 SDL_ListAdd(&element->thai_overlays, overlay); 721 SDL_free(pre); 722 } 723 724 if (cells[temp].top) { 725 SDL_ToolkitThaiOverlayX11 *overlay; 726 char *pre; 727 int temp2; 728 729 overlay = SDL_malloc(sizeof(SDL_ToolkitThaiOverlayX11)); 730 pre = SDL_iconv_string("UTF-8", "TIS-620", base_tis_str, temp); 731 overlay->str = SDL_iconv_string("UTF-8", "TIS-620", (const char *)&cells[temp].top, 1); 732 overlay->sz = SDL_strlen(overlay->str); 733 overlay->top = true; 734 X11Toolkit_GetTextWidthHeight(data, pre, SDL_strlen(pre), &overlay->rect.x, &temp2, &temp2, &temp2, NULL); 735 X11Toolkit_GetTextWidthHeight(data, overlay->str, overlay->sz, &overlay->rect.w, &overlay->rect.h, &overlay->rect.y, &temp2, NULL); 736 SDL_ListAdd(&element->thai_overlays, overlay); 737 SDL_free(pre); 738 } 739 } 740 base_tis_str[base_tis_str_sz] = '\0'; 741 742 element->str_free(element->str); 743 element->str = SDL_iconv_string("UTF-8", "TIS-620", base_tis_str, base_tis_str_sz); 744 element->sz = SDL_strlen(element->str); 745 X11Toolkit_GetTextWidthHeight(data, element->str, element->sz, &element->rect.w, &element->rect.h, &element->rect.y, &temp, &element->font_h); 746 747 SDL_free(tis_str); 748 SDL_free(cells); 749 SDL_free(base_tis_str); 750 } 751#else 752 X11Toolkit_GetTextWidthHeight(data, element->str, element->sz, &element->rect.w, &element->rect.h, &element->rect.y, &temp, &element->font_h); 753#endif 754 } 755 } else { 756 X11Toolkit_GetTextWidthHeight(data, element->str, element->sz, &element->rect.w, &element->rect.h, &element->rect.y, &temp, &element->font_h); 757 } 758 759 cursor = cursor->next; 760 } 761 762 /* Add offsets */ 763 prev = NULL; 764 cursor = list; 765 while (cursor) { 766 SDL_ToolkitTextElementX11 *element; 767 768 element = cursor->entry; 769 if (prev) { 770 element->rect.x = prev->rect.x + prev->rect.w; 771 } else { 772 element->rect.x = 0; 773 } 774 775 prev = element; 776 cursor = cursor->next; 777 } 778} 779 780 781void X11Toolkit_DrawTextElements(SDL_ToolkitWindowX11 *data, SDL_ListNode *list, int x, int y) 782{ 783 SDL_ListNode *cursor; 784 785 cursor = list; 786 787 while (cursor) { 788 SDL_ToolkitTextElementX11 *element; 789 790 element = cursor->entry; 791 if (element->type == SDL_TOOLKIT_TEXT_TYPE_X11_THAI) { 792 if (data->thai_font == SDL_TOOLKIT_THAI_FONT_X11_OFFSET) { 793#ifdef X_HAVE_UTF8_STRING 794 if (data->utf8) { 795 X11_Xutf8DrawString(data->display, data->drawable, data->font_set, data->ctx, x + element->rect.x, y + element->rect.y, element->str, element->sz); 796 } else 797#endif 798 { 799 X11_XDrawString(data->display, data->drawable, data->ctx, x + element->rect.x, y + element->rect.y, element->str, element->sz); 800 } 801 } else { 802#ifdef HAVE_LIBTHAI_H 803 SDL_ListNode *overlay_cursor; 804 805 /* Draw the base string */ 806#ifdef X_HAVE_UTF8_STRING 807 if (data->utf8) { 808 X11_Xutf8DrawString(data->display, data->drawable, data->font_set, data->ctx, x + element->rect.x, y + element->rect.y, element->str, element->sz); 809 } else 810#endif 811 { 812 X11_XDrawString(data->display, data->drawable, data->ctx, x + element->rect.x, y + element->rect.y, element->str, element->sz); 813 } 814 815 /* Draw overlays */ 816 overlay_cursor = element->thai_overlays; 817 while (overlay_cursor) { 818 SDL_ToolkitThaiOverlayX11 *overlay; 819 820 overlay = overlay_cursor->entry; 821#ifdef X_HAVE_UTF8_STRING 822 if (data->utf8) { 823 X11_Xutf8DrawString(data->display, data->drawable, data->font_set, data->ctx, x + element->rect.x + overlay->rect.x, y + overlay->rect.y, overlay->str, overlay->sz); 824 } else 825#endif 826 { 827 X11_XDrawString(data->display, data->drawable, data->ctx, x + element->rect.x + overlay->rect.x, y + element->rect.y + overlay->rect.y, overlay->str, overlay->sz); 828 } 829 830 overlay_cursor = overlay_cursor->next; 831 } 832#endif 833 } 834 } else { 835#ifdef X_HAVE_UTF8_STRING 836 if (data->utf8) { 837 X11_Xutf8DrawString(data->display, data->drawable, data->font_set, data->ctx, x + element->rect.x, y + element->rect.y, element->str, element->sz); 838 } else 839#endif 840 { 841 X11_XDrawString(data->display, data->drawable, data->ctx, x + element->rect.x, y + element->rect.y, element->str, element->sz); 842 } 843 } 844 845 cursor = cursor->next; 846 } 847} 848 849int X11Toolkit_GetTextElementsRect(SDL_ListNode *list, SDL_Rect *out) 850{ 851 SDL_ListNode *cursor; 852 int ret; 853 854 ret = 0; 855 out->x = out->y = 0; 856 out->w = out->h = 0; 857 cursor = list; 858 while (cursor) { 859 SDL_ToolkitTextElementX11 *element; 860 861 element = cursor->entry; 862 863 out->w += element->rect.w; 864 out->h = SDL_max(out->h, element->rect.h); 865 ret = SDL_max(ret, element->font_h); 866 867 cursor = cursor->next; 868 } 869 870 return ret; 871} 872 873void X11Toolkit_FreeTextElementsListContents(SDL_ListNode *list) 874{ 875 SDL_ListNode *cursor; 876 877 cursor = list; 878 while (cursor) { 879 SDL_ToolkitTextElementX11 *element; 880#ifdef HAVE_LIBTHAI_H 881 SDL_ListNode *overlay_cursor; 882#endif 883 884 element = cursor->entry; 885 886 if (element->str_free) { 887 element->str_free(element->str); 888 } 889 890#ifdef HAVE_LIBTHAI_H 891 overlay_cursor = element->thai_overlays; 892 while (overlay_cursor) { 893 SDL_ToolkitThaiOverlayX11 *overlay; 894 895 overlay = overlay_cursor->entry; 896 SDL_free(overlay->str); 897 SDL_free(overlay); 898 overlay_cursor = overlay_cursor->next; 899 } 900 SDL_ListClear(&element->thai_overlays); 901#endif 902 903 SDL_free(element); 904 905 cursor = cursor->next; 906 } 907} 908 909#define X11Toolkit_FreeTextElements(x) X11Toolkit_FreeTextElementsListContents(x); SDL_ListClear(&x) 910 911static bool X11Toolkit_ShouldFlipUI(void) 912{ 913 SDL_Locale **current_locales; 914 static const SDL_Locale rtl_locales[] = { 915 { "ar", NULL, }, 916 { "fa", "AF", }, 917 { "fa", "IR", }, 918 { "he", NULL, }, 919 { "iw", NULL, }, 920 { "yi", NULL, }, 921 { "ur", NULL, }, 922 { "ug", NULL, }, 923 { "kd", NULL, }, 924 { "pk", "PK", }, 925 { "ps", NULL, } 926 }; 927 int current_locales_sz; 928 int i; 929 930 current_locales = SDL_GetPreferredLocales(¤t_locales_sz); 931 if (current_locales_sz <= 0) { 932 return false; 933 } 934 for (i = 0; i < SDL_arraysize(rtl_locales); ++i) { 935 if (SDL_startswith(current_locales[0]->language, rtl_locales[i].language)) { 936 if (!rtl_locales[i].country) { 937 return true; 938 } else { 939 return SDL_startswith(current_locales[0]->country, rtl_locales[i].country); 940 } 941 } 942 } 943 944 return false; 945} 946 947SDL_ToolkitWindowX11 *X11Toolkit_CreateWindowStruct(SDL_Window *parent, SDL_ToolkitWindowX11 *tkparent, SDL_ToolkitWindowModeX11 mode, const SDL_MessageBoxColor *colorhints, bool create_new_display) 948{ 949 SDL_ToolkitWindowX11 *window; 950 int i; 951#ifdef SDL_USE_LIBDBUS 952 SDL_SystemTheme theme; 953#endif 954 #define ErrorFreeRetNull(x, y) SDL_SetError(x); SDL_free(y); return NULL 955 #define ErrorCloseFreeRetNull(x, y, z) X11_XCloseDisplay(z->display); SDL_SetError(x, y); SDL_free(z); return NULL 956 957 if (!SDL_X11_LoadSymbols()) { 958 return NULL; 959 } 960 961 // This code could get called from multiple threads maybe? 962 X11_XInitThreads(); 963 964 window = (SDL_ToolkitWindowX11 *)SDL_malloc(sizeof(SDL_ToolkitWindowX11)); 965 if (!window) { 966 SDL_SetError("Unable to allocate toolkit window structure"); 967 return NULL; 968 } 969 970 window->mode = mode; 971 window->tk_parent = tkparent; 972 973#if SDL_SET_LOCALE 974 if (mode == SDL_TOOLKIT_WINDOW_MODE_X11_DIALOG) { 975 window->origlocale = setlocale(LC_ALL, NULL); 976 if (window->origlocale) { 977 window->origlocale = SDL_strdup(window->origlocale); 978 if (!window->origlocale) { 979 SDL_free(window); 980 return NULL; 981 } 982 (void)setlocale(LC_ALL, ""); 983 } 984 } 985#endif 986 987 window->parent_device = NULL; 988 if (create_new_display) { 989 window->display = X11_XOpenDisplay(NULL); 990 window->display_close = true; 991 if (!window->display) { 992 ErrorFreeRetNull("Couldn't open X11 display", window); 993 } 994 } else { 995 if (parent) { 996 window->parent_device = SDL_GetVideoDevice(); 997 window->display = window->parent_device->internal->display; 998 window->display_close = false; 999 } else if (tkparent) { 1000 window->display = tkparent->display; 1001 window->display_close = false; 1002 } else { 1003 window->display = X11_XOpenDisplay(NULL); 1004 window->display_close = true; 1005 if (!window->display) { 1006 ErrorFreeRetNull("Couldn't open X11 display", window); 1007 } 1008 } 1009 } 1010 1011#ifdef SDL_VIDEO_DRIVER_X11_XRANDR 1012 int xrandr_event_base, xrandr_error_base; 1013 window->xrandr = X11_XRRQueryExtension(window->display, &xrandr_event_base, &xrandr_error_base); 1014#endif 1015 1016#ifndef NO_SHARED_MEMORY 1017 window->shm_pixmap = False; 1018 window->shm = X11_XShmQueryExtension(window->display) ? SDL_X11_HAVE_SHM : false; 1019 if (window->shm) { 1020 int major; 1021 int minor; 1022 1023 X11_XShmQueryVersion(window->display, &major, &minor, &window->shm_pixmap); 1024 if (window->shm_pixmap) { 1025 if (X11_XShmPixmapFormat(window->display) != ZPixmap) { 1026 window->shm_pixmap = False; 1027 } 1028 } 1029 } 1030#endif 1031 1032 /* Scale/Xsettings */ 1033 window->pixmap = false; 1034 window->xsettings_first_time = true; 1035 window->xsettings = xsettings_client_new(window->display, DefaultScreen(window->display), X11Toolkit_SettingsNotify, NULL, window); 1036 window->xsettings_first_time = false; 1037 window->scale = X11_GetGlobalContentScale(window->display, window->xsettings); 1038 if (window->scale < 1) { 1039 window->scale = 1; 1040 } 1041 window->iscale = (int)SDL_ceilf(window->scale); 1042 if (SDL_roundf(window->scale) == window->scale) { 1043 window->scale = 0; 1044 } 1045 1046 /* Fonts */ 1047 X11Toolkit_InitWindowFonts(window); 1048 1049 /* Color hints */ 1050#ifdef SDL_USE_LIBDBUS 1051 theme = SDL_SYSTEM_THEME_LIGHT; 1052 if (SDL_SystemTheme_Init()) { 1053 theme = SDL_SystemTheme_Get(); 1054 } 1055#endif 1056 1057 if (!colorhints) { 1058#ifdef SDL_USE_LIBDBUS 1059 switch (theme) { 1060 case SDL_SYSTEM_THEME_DARK: 1061 colorhints = g_default_colors_dark; 1062 break; 1063#if 0 1064 case SDL_SYSTEM_THEME_LIGHT_HIGH_CONTRAST: 1065 colorhints = g_default_colors_light_high_contrast; 1066 break; 1067 case SDL_SYSTEM_THEME_DARK_HIGH_CONTRAST: 1068 colorhints = g_default_colors_dark_high_contrast; 1069 break; 1070#endif 1071 default: 1072 colorhints = g_default_colors; 1073 } 1074#else 1075 colorhints = g_default_colors; 1076#endif 1077 } 1078 window->color_hints = colorhints; 1079 1080 /* Convert colors to 16 bpc XColor format */ 1081 for (i = 0; i < SDL_MESSAGEBOX_COLOR_COUNT; i++) { 1082 window->xcolor[i].flags = DoRed|DoGreen|DoBlue; 1083 window->xcolor[i].red = colorhints[i].r * 257; 1084 window->xcolor[i].green = colorhints[i].g * 257; 1085 window->xcolor[i].blue = colorhints[i].b * 257; 1086 } 1087 1088 /* Generate bevel and pressed colors */ 1089 window->xcolor_bevel_l1.flags = DoRed|DoGreen|DoBlue; 1090 window->xcolor_bevel_l1.red = SDL_clamp(window->xcolor[SDL_MESSAGEBOX_COLOR_BUTTON_BORDER].red + 12500, 0, 65535); 1091 window->xcolor_bevel_l1.green = SDL_clamp(window->xcolor[SDL_MESSAGEBOX_COLOR_BUTTON_BORDER].green + 12500, 0, 65535); 1092 window->xcolor_bevel_l1.blue = SDL_clamp(window->xcolor[SDL_MESSAGEBOX_COLOR_BUTTON_BORDER].blue + 12500, 0, 65535); 1093 1094 window->xcolor_bevel_l2.flags = DoRed|DoGreen|DoBlue; 1095 window->xcolor_bevel_l2.red = SDL_clamp(window->xcolor[SDL_MESSAGEBOX_COLOR_BUTTON_BORDER].red + 32500, 0, 65535); 1096 window->xcolor_bevel_l2.green = SDL_clamp(window->xcolor[SDL_MESSAGEBOX_COLOR_BUTTON_BORDER].green + 32500, 0, 65535); 1097 window->xcolor_bevel_l2.blue = SDL_clamp(window->xcolor[SDL_MESSAGEBOX_COLOR_BUTTON_BORDER].blue + 32500, 0, 65535); 1098 1099 window->xcolor_bevel_d.flags = DoRed|DoGreen|DoBlue; 1100 window->xcolor_bevel_d.red = SDL_clamp(window->xcolor[SDL_MESSAGEBOX_COLOR_BUTTON_BORDER].red - 22500, 0, 65535); 1101 window->xcolor_bevel_d.green = SDL_clamp(window->xcolor[SDL_MESSAGEBOX_COLOR_BUTTON_BORDER].green - 22500, 0, 65535); 1102 window->xcolor_bevel_d.blue = SDL_clamp(window->xcolor[SDL_MESSAGEBOX_COLOR_BUTTON_BORDER].blue - 22500, 0, 65535); 1103 1104 window->xcolor_pressed.flags = DoRed|DoGreen|DoBlue; 1105 window->xcolor_pressed.red = SDL_clamp(window->xcolor[SDL_MESSAGEBOX_COLOR_BUTTON_BACKGROUND].red - 12500, 0, 65535); 1106 window->xcolor_pressed.green = SDL_clamp(window->xcolor[SDL_MESSAGEBOX_COLOR_BUTTON_BACKGROUND].green - 12500, 0, 65535); 1107 window->xcolor_pressed.blue = SDL_clamp(window->xcolor[SDL_MESSAGEBOX_COLOR_BUTTON_BACKGROUND].blue - 12500, 0, 65535); 1108 1109 window->xcolor_disabled_text.flags = DoRed|DoGreen|DoBlue; 1110 window->xcolor_disabled_text.red = SDL_clamp(window->xcolor[SDL_MESSAGEBOX_COLOR_TEXT].red + 19500, 0, 65535); 1111 window->xcolor_disabled_text.green = SDL_clamp(window->xcolor[SDL_MESSAGEBOX_COLOR_TEXT].green + 19500, 0, 65535); 1112 window->xcolor_disabled_text.blue = SDL_clamp(window->xcolor[SDL_MESSAGEBOX_COLOR_TEXT].blue + 19500, 0, 65535); 1113 1114 /* Screen */ 1115 window->parent = parent; 1116 if (parent) { 1117 SDL_DisplayData *displaydata = SDL_GetDisplayDriverDataForWindow(parent); 1118 window->screen = displaydata->screen; 1119 } else { 1120 window->screen = DefaultScreen(window->display); 1121 } 1122 1123 /* Visuals */ 1124 if (mode == SDL_TOOLKIT_WINDOW_MODE_X11_CHILD) { 1125 window->visual = parent->internal->visual; 1126 window->cmap = parent->internal->colormap; 1127 X11_GetVisualInfoFromVisual(window->display, window->visual, &window->vi); 1128 window->depth = window->vi.depth; 1129 } else { 1130 window->visual = DefaultVisual(window->display, window->screen); 1131 window->cmap = DefaultColormap(window->display, window->screen); 1132 window->depth = DefaultDepth(window->display, window->screen); 1133 X11_GetVisualInfoFromVisual(window->display, window->visual, &window->vi); 1134 } 1135 1136 /* Allocate colors */ 1137 for (i = 0; i < SDL_MESSAGEBOX_COLOR_COUNT; i++) { 1138 X11_XAllocColor(window->display, window->cmap, &window->xcolor[i]); 1139 } 1140 X11_XAllocColor(window->display, window->cmap, &window->xcolor_bevel_l1); 1141 X11_XAllocColor(window->display, window->cmap, &window->xcolor_bevel_l2); 1142 X11_XAllocColor(window->display, window->cmap, &window->xcolor_bevel_d); 1143 X11_XAllocColor(window->display, window->cmap, &window->xcolor_pressed); 1144 X11_XAllocColor(window->display, window->cmap, &window->xcolor_disabled_text); 1145 1146 /* Control list */ 1147 window->has_focus = false; 1148 window->controls = NULL; 1149 window->controls_sz = 0; 1150 window->dyn_controls_sz = 0; 1151 window->fiddled_control = NULL; 1152 window->dyn_controls = NULL; 1153 1154 /* Menu windows */ 1155 window->popup_windows = NULL; 1156 1157 /* BIDI engine */ 1158#ifdef HAVE_FRIBIDI_H 1159 window->fribidi = SDL_FriBidi_Create(); 1160#endif 1161 1162#ifdef HAVE_LIBTHAI_H 1163 window->th = SDL_LibThai_Create(); 1164#endif 1165 1166 /* Interface direction */ 1167 window->flip_interface = X11Toolkit_ShouldFlipUI(); 1168 1169 return window; 1170} 1171 1172static void X11Toolkit_AddControlToWindow(SDL_ToolkitWindowX11 *window, SDL_ToolkitControlX11 *control) { 1173 /* Add to controls list */ 1174 window->controls_sz++; 1175 if (window->controls_sz == 1) { 1176 window->controls = (struct SDL_ToolkitControlX11 **)SDL_malloc(sizeof(struct SDL_ToolkitControlX11 *)); 1177 } else { 1178 window->controls = (struct SDL_ToolkitControlX11 **)SDL_realloc(window->controls, sizeof(struct SDL_ToolkitControlX11 *) * window->controls_sz); 1179 } 1180 window->controls[window->controls_sz - 1] = control; 1181 1182 /* If dynamic, add it to the dynamic controls list too */ 1183 if (control->dynamic) { 1184 window->dyn_controls_sz++; 1185 if (window->dyn_controls_sz == 1) { 1186 window->dyn_controls = (struct SDL_ToolkitControlX11 **)SDL_malloc(sizeof(struct SDL_ToolkitControlX11 *)); 1187 } else { 1188 window->dyn_controls = (struct SDL_ToolkitControlX11 **)SDL_realloc(window->dyn_controls, sizeof(struct SDL_ToolkitControlX11 *) * window->dyn_controls_sz); 1189 } 1190 window->dyn_controls[window->dyn_controls_sz - 1] = control; 1191 } 1192 1193 /* If selected, set currently focused control to it */ 1194 if (control->selected) { 1195 window->focused_control = control; 1196 } 1197} 1198 1199bool X11Toolkit_CreateWindowRes(SDL_ToolkitWindowX11 *data, int w, int h, int cx, int cy, char *title) 1200{ 1201 int x, y; 1202 XSizeHints *sizehints; 1203 XSetWindowAttributes wnd_attr; 1204 Atom _NET_WM_WINDOW_TYPE, _NET_WM_WINDOW_TYPE_DIALOG, _NET_WM_WINDOW_TYPE_DROPDOWN_MENU, _NET_WM_WINDOW_TYPE_TOOLTIP; 1205 SDL_WindowData *windowdata = NULL; 1206 Display *display = data->display; 1207 XGCValues ctx_vals; 1208 Window root_win; 1209 Window parent_win; 1210 unsigned long gcflags = GCForeground | GCBackground; 1211 unsigned long valuemask; 1212#ifdef SDL_VIDEO_DRIVER_X11_XRANDR 1213#ifdef XRANDR_DISABLED_BY_DEFAULT 1214 const bool use_xrandr_by_default = false; 1215#else 1216 const bool use_xrandr_by_default = true; 1217#endif 1218#endif 1219 1220 if (data->scale == 0) { 1221 data->window_width = w; 1222 data->window_height = h; 1223 } else { 1224 data->window_width = SDL_lroundf((w/data->iscale) * data->scale); 1225 data->window_height = SDL_lroundf((h/data->iscale) * data->scale); 1226 data->pixmap_width = w; 1227 data->pixmap_height = h; 1228 data->pixmap = true; 1229 } 1230 1231 if (data->parent) { 1232 windowdata = data->parent->internal; 1233 } 1234 1235 valuemask = CWEventMask | CWColormap; 1236 data->event_mask = ExposureMask | 1237 ButtonPressMask | ButtonReleaseMask | KeyPressMask | KeyReleaseMask | 1238 StructureNotifyMask | FocusChangeMask | PointerMotionMask; 1239 wnd_attr.event_mask = data->event_mask; 1240 wnd_attr.colormap = data->cmap; 1241 if (data->mode == SDL_TOOLKIT_WINDOW_MODE_X11_MENU || data->mode== SDL_TOOLKIT_WINDOW_MODE_X11_TOOLTIP) { 1242 valuemask |= CWOverrideRedirect | CWSaveUnder; 1243 wnd_attr.save_under = True; 1244 wnd_attr.override_redirect = True; 1245 } 1246 root_win = RootWindow(display, data->screen); 1247 if (data->mode == SDL_TOOLKIT_WINDOW_MODE_X11_CHILD) { 1248 parent_win = windowdata->xwindow; 1249 } else { 1250 parent_win = root_win; 1251 } 1252 1253 data->window = X11_XCreateWindow( 1254 display, parent_win, 1255 0, 0, 1256 data->window_width, data->window_height, 1257 0, data->depth, InputOutput, data->visual, 1258 valuemask, &wnd_attr); 1259 if (data->window == None) { 1260 return SDL_SetError("Couldn't create X window"); 1261 } 1262 1263 if (windowdata && data->mode == SDL_TOOLKIT_WINDOW_MODE_X11_DIALOG) { 1264 Atom _NET_WM_STATE = X11_XInternAtom(display, "_NET_WM_STATE", False); 1265 Atom stateatoms[16]; 1266 size_t statecount = 0; 1267 // Set some message-boxy window states when attached to a parent window... 1268 // we skip the taskbar since this will pop to the front when the parent window is clicked in the taskbar, etc 1269 stateatoms[statecount++] = X11_XInternAtom(display, "_NET_WM_STATE_SKIP_TASKBAR", False); 1270 stateatoms[statecount++] = X11_XInternAtom(display, "_NET_WM_STATE_SKIP_PAGER", False); 1271 stateatoms[statecount++] = X11_XInternAtom(display, "_NET_WM_STATE_FOCUSED", False); 1272 stateatoms[statecount++] = X11_XInternAtom(display, "_NET_WM_STATE_MODAL", False); 1273 SDL_assert(statecount <= SDL_arraysize(stateatoms)); 1274 X11_XChangeProperty(display, data->window, _NET_WM_STATE, XA_ATOM, 32, 1275 PropModeReplace, (unsigned char *)stateatoms, statecount); 1276 } 1277 1278 if (windowdata && data->mode != SDL_TOOLKIT_WINDOW_MODE_X11_CHILD) { 1279 X11_XSetTransientForHint(display, data->window, windowdata->xwindow); 1280 } 1281 1282 if (data->tk_parent) { 1283 X11_XSetTransientForHint(display, data->window, data->tk_parent->window); 1284 } 1285 1286 SDL_X11_SetWindowTitle(display, data->window, title); 1287 1288 // Let the window manager the type of the window 1289 if (data->mode == SDL_TOOLKIT_WINDOW_MODE_X11_DIALOG) { 1290 _NET_WM_WINDOW_TYPE = X11_XInternAtom(display, "_NET_WM_WINDOW_TYPE", False); 1291 _NET_WM_WINDOW_TYPE_DIALOG = X11_XInternAtom(display, "_NET_WM_WINDOW_TYPE_DIALOG", False); 1292 X11_XChangeProperty(display, data->window, _NET_WM_WINDOW_TYPE, XA_ATOM, 32, 1293 PropModeReplace, 1294 (unsigned char *)&_NET_WM_WINDOW_TYPE_DIALOG, 1); 1295 } else if (data->mode == SDL_TOOLKIT_WINDOW_MODE_X11_MENU) { 1296 _NET_WM_WINDOW_TYPE = X11_XInternAtom(display, "_NET_WM_WINDOW_TYPE", False); 1297 _NET_WM_WINDOW_TYPE_DROPDOWN_MENU = X11_XInternAtom(display, "_NET_WM_WINDOW_TYPE_DROPDOWN_MENU", False); 1298 X11_XChangeProperty(display, data->window, _NET_WM_WINDOW_TYPE, XA_ATOM, 32, 1299 PropModeReplace, 1300 (unsigned char *)&_NET_WM_WINDOW_TYPE_DROPDOWN_MENU, 1); 1301 } else if (data->mode == SDL_TOOLKIT_WINDOW_MODE_X11_TOOLTIP) { 1302 _NET_WM_WINDOW_TYPE = X11_XInternAtom(display, "_NET_WM_WINDOW_TYPE", False); 1303 _NET_WM_WINDOW_TYPE_TOOLTIP = X11_XInternAtom(display, "_NET_WM_WINDOW_TYPE_TOOLTIP", False); 1304 X11_XChangeProperty(display, data->window, _NET_WM_WINDOW_TYPE, XA_ATOM, 32, 1305 PropModeReplace, 1306 (unsigned char *)&_NET_WM_WINDOW_TYPE_TOOLTIP, 1); 1307 } 1308 1309 // Allow the window to be deleted by the window manager 1310 data->wm_delete_message = X11_XInternAtom(display, "WM_DELETE_WINDOW", False); 1311 X11_XSetWMProtocols(display, data->window, &data->wm_delete_message, 1); 1312 data->wm_protocols = X11_XInternAtom(display, "WM_PROTOCOLS", False); 1313 1314 if (data->mode == SDL_TOOLKIT_WINDOW_MODE_X11_MENU || data->mode== SDL_TOOLKIT_WINDOW_MODE_X11_TOOLTIP) { 1315 x = cx; 1316 y = cy; 1317 goto MOVEWINDOW; 1318 } 1319 if (windowdata) { 1320 XWindowAttributes attrib; 1321 Window dummy; 1322 1323 X11_XGetWindowAttributes(display, windowdata->xwindow, &attrib); 1324 x = attrib.x + (attrib.width - data->window_width) / 2; 1325 y = attrib.y + (attrib.height - data->window_height) / 3; 1326 X11_XTranslateCoordinates(display, windowdata->xwindow, RootWindow(display, data->screen), x, y, &x, &y, &dummy); 1327 } else { 1328 const SDL_VideoDevice *dev = SDL_GetVideoDevice(); 1329 if (dev && dev->displays && dev->num_displays > 0) { 1330 const SDL_VideoDisplay *dpy = dev->displays[0]; 1331 const SDL_DisplayData *dpydata = dpy->internal; 1332 x = dpydata->x + ((dpy->current_mode->w - data->window_width) / 2); 1333 y = dpydata->y + ((dpy->current_mode->h - data->window_height) / 3); 1334 } 1335#ifdef SDL_VIDEO_DRIVER_X11_XRANDR 1336 else if (SDL_GetHintBoolean(SDL_HINT_VIDEO_X11_XRANDR, use_xrandr_by_default) && data->xrandr) { 1337 XRRScreenResources *screen_res; 1338 XRRCrtcInfo *crtc_info; 1339 RROutput default_out; 1340 1341 screen_res = X11_XRRGetScreenResourcesCurrent(display, root_win); 1342 if (!screen_res) { 1343 goto NOXRANDR; 1344 } 1345 1346 default_out = X11_XRRGetOutputPrimary(display, root_win); 1347 if (default_out != None) { 1348 XRROutputInfo *out_info; 1349 1350 out_info = X11_XRRGetOutputInfo(display, screen_res, default_out); 1351 if (out_info->connection != RR_Connected) { 1352 X11_XRRFreeOutputInfo(out_info); 1353 goto FIRSTOUTPUTXRANDR; 1354 } 1355 1356 if (out_info->crtc != None) { 1357 crtc_info = X11_XRRGetCrtcInfo(display, screen_res, out_info->crtc); 1358 } else if (out_info->ncrtc > 0) { 1359 crtc_info = X11_XRRGetCrtcInfo(display, screen_res, out_info->crtcs[0]); 1360 } else { 1361 crtc_info = NULL; 1362 } 1363 1364 if (crtc_info) { 1365 x = (crtc_info->width - data->window_width) / 2; 1366 y = (crtc_info->height - data->window_height) / 3; 1367 X11_XRRFreeOutputInfo(out_info); 1368 X11_XRRFreeCrtcInfo(crtc_info); 1369 X11_XRRFreeScreenResources(screen_res); 1370 } else { 1371 X11_XRRFreeOutputInfo(out_info); 1372 goto NOXRANDR; 1373 } 1374 } else { 1375 FIRSTOUTPUTXRANDR: 1376 if (screen_res->noutput > 0) { 1377 XRROutputInfo *out_info; 1378 1379 out_info = X11_XRRGetOutputInfo(display, screen_res, screen_res->outputs[0]); 1380 if (!out_info) { 1381 goto FIRSTCRTCXRANDR; 1382 } 1383 1384 if (out_info->crtc != None) { 1385 crtc_info = X11_XRRGetCrtcInfo(display, screen_res, out_info->crtc); 1386 } else if (out_info->ncrtc > 0) { 1387 crtc_info = X11_XRRGetCrtcInfo(display, screen_res, out_info->crtcs[0]); 1388 } else { 1389 crtc_info = NULL; 1390 } 1391 1392 if (!crtc_info) { 1393 X11_XRRFreeOutputInfo(out_info); 1394 goto FIRSTCRTCXRANDR; 1395 } 1396 1397 x = (crtc_info->width - data->window_width) / 2; 1398 y = (crtc_info->height - data->window_height) / 3; 1399 X11_XRRFreeOutputInfo(out_info); 1400 X11_XRRFreeCrtcInfo(crtc_info); 1401 X11_XRRFreeScreenResources(screen_res); 1402 goto MOVEWINDOW; 1403 } 1404 1405 FIRSTCRTCXRANDR: 1406 if (!screen_res->ncrtc) { 1407 X11_XRRFreeScreenResources(screen_res); 1408 goto NOXRANDR; 1409 } 1410 1411 crtc_info = X11_XRRGetCrtcInfo(display, screen_res, screen_res->crtcs[0]); 1412 if (crtc_info) { 1413 x = (crtc_info->width - data->window_width) / 2; 1414 y = (crtc_info->height - data->window_height) / 3; 1415 X11_XRRFreeCrtcInfo(crtc_info); 1416 X11_XRRFreeScreenResources(screen_res); 1417 } else { 1418 X11_XRRFreeScreenResources(screen_res); 1419 goto NOXRANDR; 1420 } 1421 } 1422 } 1423#endif 1424 else { 1425 // oh well. This will misposition on a multi-head setup. Init first next time. 1426 NOXRANDR: 1427 x = (DisplayWidth(display, data->screen) - data->window_width) / 2; 1428 y = (DisplayHeight(display, data->screen) - data->window_height) / 3; 1429 } 1430 } 1431 MOVEWINDOW: 1432 X11_XMoveWindow(display, data->window, x, y); 1433 data->window_x = x; 1434 data->window_y = y; 1435 1436 sizehints = X11_XAllocSizeHints(); 1437 if (sizehints) { 1438 sizehints->flags = USPosition | USSize | PMaxSize | PMinSize; 1439 sizehints->x = x; 1440 sizehints->y = y; 1441 sizehints->width = data->window_width; 1442 sizehints->height = data->window_height; 1443 1444 sizehints->min_width = sizehints->max_width = data->window_width; 1445 sizehints->min_height = sizehints->max_height = data->window_height; 1446 1447 X11_XSetWMNormalHints(display, data->window, sizehints); 1448 1449 X11_XFree(sizehints); 1450 } 1451 1452 X11_XMapRaised(display, data->window); 1453 1454 data->drawable = data->window; 1455#ifdef SDL_VIDEO_DRIVER_X11_XDBE 1456 // Initialise a back buffer for double buffering 1457 if (SDL_X11_HAVE_XDBE && !data->pixmap) { 1458 int xdbe_major, xdbe_minor; 1459 if (X11_XdbeQueryExtension(display, &xdbe_major, &xdbe_minor) != 0) { 1460 data->xdbe = true; 1461 data->buf = X11_XdbeAllocateBackBufferName(display, data->window, XdbeUndefined); 1462 data->drawable = data->buf; 1463 } else { 1464 data->xdbe = false; 1465 } 1466 } 1467#endif 1468 1469 X11Toolkit_InitWindowPixmap(data); 1470 1471 SDL_zero(ctx_vals); 1472 ctx_vals.foreground = data->xcolor[SDL_MESSAGEBOX_COLOR_BACKGROUND].pixel; 1473 ctx_vals.background = data->xcolor[SDL_MESSAGEBOX_COLOR_BACKGROUND].pixel; 1474 if (!data->utf8) { 1475 gcflags |= GCFont; 1476 ctx_vals.font = data->font_struct->fid; 1477 } 1478 data->ctx = X11_XCreateGC(data->display, data->drawable, gcflags, &ctx_vals); 1479 if (data->ctx == None) { 1480 return SDL_SetError("Couldn't create graphics context"); 1481 } 1482 1483 data->close = false; 1484 data->key_control_esc = data->key_control_enter = NULL; 1485 if (!data->pixmap) { 1486 data->ev_scale = data->ev_iscale = 1; 1487 } else { 1488 data->ev_scale = data->scale; 1489 data->ev_iscale = data->iscale; 1490 } 1491 1492#if SDL_GRAB 1493 if (data->mode == SDL_TOOLKIT_WINDOW_MODE_X11_MENU || data->mode== SDL_TOOLKIT_WINDOW_MODE_X11_TOOLTIP) { 1494 X11_XGrabPointer(display, data->window, False, ButtonPressMask | ButtonReleaseMask | PointerMotionMask, GrabModeAsync, GrabModeAsync, None, None, CurrentTime); 1495 X11_XGrabKeyboard(display, data->window, False, GrabModeAsync, GrabModeAsync, CurrentTime); 1496 } 1497#endif 1498 1499 return true; 1500} 1501 1502static void X11Toolkit_DrawWindow(SDL_ToolkitWindowX11 *data) { 1503 SDL_Rect rect; 1504 int i; 1505 1506#ifdef SDL_VIDEO_DRIVER_X11_XDBE 1507 if (SDL_X11_HAVE_XDBE && data->xdbe && !data->pixmap) { 1508 X11_XdbeBeginIdiom(data->display); 1509 } 1510#endif 1511 1512 X11_XSetForeground(data->display, data->ctx, data->xcolor[SDL_MESSAGEBOX_COLOR_BACKGROUND].pixel); 1513 if (data->pixmap) { 1514 X11_XFillRectangle(data->display, data->drawable, data->ctx, 0, 0, data->pixmap_width, data->pixmap_height); 1515 } else { 1516 X11_XFillRectangle(data->display, data->drawable, data->ctx, 0, 0, data->window_width, data->window_height); 1517 } 1518 1519 for (i = 0; i < data->controls_sz; i++) { 1520 SDL_ToolkitControlX11 *control; 1521 1522 control = data->controls[i]; 1523 if (control) { 1524 if (control->func_draw) { 1525 control->func_draw(control); 1526 } 1527 } 1528 } 1529 1530#ifdef SDL_VIDEO_DRIVER_X11_XDBE 1531 if (SDL_X11_HAVE_XDBE && data->xdbe && !data->pixmap) { 1532 XdbeSwapInfo swap_info; 1533 swap_info.swap_window = data->window; 1534 swap_info.swap_action = XdbeUndefined; 1535 X11_XdbeSwapBuffers(data->display, &swap_info, 1); 1536 X11_XdbeEndIdiom(data->display); 1537 } 1538#endif 1539 1540 if (data->pixmap) { 1541 SDL_Surface *scale_surface; 1542 1543 rect.x = rect.y = 0; 1544 rect.w = data->window_width; 1545 rect.h = data->window_height; 1546#ifndef NO_SHARED_MEMORY 1547 if (data->shm) { 1548 if (data->shm_pixmap) { 1549 X11_XFlush(data->display); 1550 X11_XSync(data->display, false); 1551 scale_surface = SDL_CreateSurfaceFrom(data->pixmap_width, data->pixmap_height, X11_GetPixelFormatFromVisualInfo(data->display, &data->vi), data->shm_info.shmaddr, data->shm_bytes_per_line); 1552 SDL_BlitSurfaceScaled(scale_surface, NULL, scale_surface, &rect, SDL_SCALEMODE_LINEAR); 1553 SDL_DestroySurface(scale_surface); 1554 X11_XCopyArea(data->display, data->drawable, data->window, data->ctx, 0, 0, data->window_width, data->window_height, 0, 0); 1555 } else { 1556 X11_XShmGetImage(data->display, data->drawable, data->image, 0, 0, AllPlanes); 1557 scale_surface = SDL_CreateSurfaceFrom(data->pixmap_width, data->pixmap_height, X11_GetPixelFormatFromVisualInfo(data->display, &data->vi), data->image->data, data->image->bytes_per_line); 1558 SDL_BlitSurfaceScaled(scale_surface, NULL, scale_surface, &rect, SDL_SCALEMODE_LINEAR); 1559 X11_XShmPutImage(data->display, data->window, data->ctx, data->image, 0, 0, 0, 0, data->window_width, data->window_height, False); 1560 } 1561 } else 1562#endif 1563 { 1564 XImage *image; 1565 1566 image = X11_XGetImage(data->display, data->drawable, 0, 0 , data->pixmap_width, data->pixmap_height, AllPlanes, ZPixmap); 1567 scale_surface = SDL_CreateSurfaceFrom(data->pixmap_width, data->pixmap_height, X11_GetPixelFormatFromVisualInfo(data->display, &data->vi), image->data, image->bytes_per_line); 1568 SDL_BlitSurfaceScaled(scale_surface, NULL, scale_surface, &rect, SDL_SCALEMODE_LINEAR); 1569 X11_XPutImage(data->display, data->window, data->ctx, image, 0, 0, 0, 0, data->window_width, data->window_height); 1570 1571 XDestroyImage(image); 1572 SDL_DestroySurface(scale_surface); 1573 } 1574 } 1575 1576 X11_XFlush(data->display); 1577} 1578 1579static SDL_ToolkitControlX11 *X11Toolkit_GetControlMouseIsOn(SDL_ToolkitWindowX11 *data, int x, int y) 1580{ 1581 int i; 1582 1583 for (i = 0; i < data->controls_sz; i++) { 1584 SDL_Rect *rect = &data->controls[i]->rect; 1585 if ((x >= rect->x) && 1586 (x <= (rect->x + rect->w)) && 1587 (y >= rect->y) && 1588 (y <= (rect->y + rect->h))) { 1589 return data->controls[i]; 1590 } 1591 } 1592 1593 return NULL; 1594} 1595 1596// NOLINTNEXTLINE(readability-non-const-parameter): cannot make XPointer a const pointer due to typedef 1597static Bool X11Toolkit_EventTest(Display *display, XEvent *event, XPointer arg) 1598{ 1599 SDL_ToolkitWindowX11 *data = (SDL_ToolkitWindowX11 *)arg; 1600 1601 if (event->xany.display != data->display) { 1602 return False; 1603 } 1604 1605 if (event->xany.window == data->window) { 1606 return True; 1607 } 1608 1609 return False; 1610} 1611 1612void X11Toolkit_ProcessWindowEvents(SDL_ToolkitWindowX11 *data, XEvent *e) { 1613 /* If X11_XFilterEvent returns True, then some input method has filtered the 1614 event, and the client should discard the event. */ 1615 if ((e->type != Expose) && X11_XFilterEvent(e, None)) { 1616 return; 1617 } 1618 1619 data->draw = false; 1620 data->e = e; 1621 1622 switch (e->type) { 1623 case Expose: 1624 data->draw = true; 1625 break; 1626 case ClientMessage: 1627 if (e->xclient.message_type == data->wm_protocols && 1628 e->xclient.format == 32 && 1629 e->xclient.data.l[0] == data->wm_delete_message) { 1630 data->close = true; 1631 } 1632 break; 1633 case FocusIn: 1634 data->has_focus = true; 1635 break; 1636 case FocusOut: 1637 data->has_focus = false; 1638 if (data->fiddled_control) { 1639 data->fiddled_control->selected = false; 1640 } 1641 data->fiddled_control = NULL; 1642 for (data->ev_i = 0; data->ev_i < data->controls_sz; data->ev_i++) { 1643 data->controls[data->ev_i]->state = SDL_TOOLKIT_CONTROL_STATE_X11_NORMAL; 1644 } 1645 break; 1646 case MotionNotify: 1647 if (data->has_focus) { 1648 data->previous_control = data->fiddled_control; 1649 data->fiddled_control = X11Toolkit_GetControlMouseIsOn(data, SDL_lroundf((e->xbutton.x/ data->ev_scale)* data->ev_iscale), SDL_lroundf((e->xbutton.y/ data->ev_scale)* data->ev_iscale)); 1650 if (data->previous_control) { 1651 data->previous_control->state = SDL_TOOLKIT_CONTROL_STATE_X11_NORMAL; 1652 if (data->previous_control->func_on_state_change) { 1653 data->previous_control->func_on_state_change(data->previous_control); 1654 } 1655 data->draw = true; 1656 } 1657 if (data->fiddled_control) { 1658 if (data->fiddled_control->dynamic) { 1659 data->fiddled_control->state = SDL_TOOLKIT_CONTROL_STATE_X11_HOVER; 1660 if (data->fiddled_control->func_on_state_change) { 1661 data->fiddled_control->func_on_state_change(data->fiddled_control); 1662 } 1663 data->draw = true; 1664 } else { 1665 data->fiddled_control = NULL; 1666 } 1667 } 1668 } 1669 break; 1670 case ButtonPress: 1671 data->previous_control = data->fiddled_control; 1672 if (data->previous_control) { 1673 data->previous_control->state = SDL_TOOLKIT_CONTROL_STATE_X11_NORMAL; 1674 if (data->previous_control->func_on_state_change) { 1675 data->previous_control->func_on_state_change(data->previous_control); 1676 } 1677 data->draw = true; 1678 } 1679 if (e->xbutton.button == Button1) { 1680 data->fiddled_control = X11Toolkit_GetControlMouseIsOn(data, SDL_lroundf((e->xbutton.x/ data->ev_scale)* data->ev_iscale), SDL_lroundf((e->xbutton.y/ data->ev_scale)* data->ev_iscale)); 1681 if (data->fiddled_control) { 1682 data->fiddled_control->state = SDL_TOOLKIT_CONTROL_STATE_X11_PRESSED_HELD; 1683 if (data->fiddled_control->func_on_state_change) { 1684 data->fiddled_control->func_on_state_change(data->fiddled_control); 1685 } 1686 data->draw = true; 1687 } 1688 } 1689 break; 1690 case ButtonRelease: 1691 if (data->mode == SDL_TOOLKIT_WINDOW_MODE_X11_MENU || data->mode== SDL_TOOLKIT_WINDOW_MODE_X11_TOOLTIP) { 1692 int cx; 1693 int cy; 1694 1695 cx = e->xbutton.x; 1696 cy = e->xbutton.y; 1697 1698 if (cy < 0 || cx < 0) { 1699 data->close = true; 1700 } 1701 1702 if (cy > data->window_height || cx > data->window_width) { 1703 data->close = true; 1704 } 1705 } 1706 1707 if ((e->xbutton.button == Button1) && (data->fiddled_control)) { 1708 SDL_ToolkitControlX11 *control; 1709 1710 control = X11Toolkit_GetControlMouseIsOn(data, SDL_lroundf((e->xbutton.x/ data->ev_scale)* data->ev_iscale), SDL_lroundf((e->xbutton.y/ data->ev_scale)* data->ev_iscale)); 1711 if (data->fiddled_control == control) { 1712 data->fiddled_control->state = SDL_TOOLKIT_CONTROL_STATE_X11_PRESSED; 1713 if (data->fiddled_control->func_on_state_change) { 1714 data->fiddled_control->func_on_state_change(data->fiddled_control); 1715 } 1716 data->fiddled_control->state = SDL_TOOLKIT_CONTROL_STATE_X11_NORMAL; 1717 data->draw = true; 1718 } 1719 } 1720 break; 1721 case KeyPress: 1722 data->last_key_pressed = X11_XLookupKeysym(&e->xkey, 0); 1723 1724 if (data->last_key_pressed == XK_Escape) { 1725 for (data->ev_i = 0; data->ev_i < data->controls_sz; data->ev_i++) { 1726 if(data->controls[data->ev_i]->is_default_esc) { 1727 data->controls[data->ev_i]->state = SDL_TOOLKIT_CONTROL_STATE_X11_PRESSED; 1728 data->draw = true; 1729 data->key_control_esc = data->controls[data->ev_i]; 1730 } 1731 } 1732 } else if ((data->last_key_pressed == XK_Return) || (data->last_key_pressed == XK_KP_Enter)) { 1733 for (data->ev_i = 0; data->ev_i < data->controls_sz; data->ev_i++) { 1734 if(data->controls[data->ev_i]->selected) { 1735 data->controls[data->ev_i]->state = SDL_TOOLKIT_CONTROL_STATE_X11_PRESSED; 1736 data->draw = true; 1737 data->key_control_enter = data->controls[data->ev_i]; 1738 } 1739 } 1740 } 1741 break; 1742 case KeyRelease: 1743 { 1744 KeySym key = X11_XLookupKeysym(&e->xkey, 0); 1745 1746 // If this is a key release for something we didn't get the key down for, then bail. 1747 if (key != data->last_key_pressed) { 1748 break; 1749 } 1750 1751 if (key == XK_Escape) { 1752 if (data->key_control_esc) { 1753 if (data->key_control_esc->func_on_state_change) { 1754 data->key_control_esc->func_on_state_change(data->key_control_esc); 1755 } 1756 } 1757 } else if ((key == XK_Return) || (key == XK_KP_Enter)) { 1758 if (data->key_control_enter) { 1759 if (data->key_control_enter->func_on_state_change) { 1760 data->key_control_enter->func_on_state_change(data->key_control_enter); 1761 } 1762 } 1763 } else if (key == XK_Tab || key == XK_Left || key == XK_Right) { 1764 if (data->focused_control) { 1765 data->focused_control->selected = false; 1766 } 1767 data->draw = true; 1768 for (data->ev_i = 0; data->ev_i < data->dyn_controls_sz; data->ev_i++) { 1769 if (data->dyn_controls[data->ev_i] == data->focused_control) { 1770 int next_index; 1771 1772 if (key == XK_Left) { 1773 next_index = data->ev_i - 1; 1774 } else { 1775 next_index = data->ev_i + 1; 1776 } 1777 if ((next_index >= data->dyn_controls_sz) || (next_index < 0)) { 1778 if (key == XK_Right || key == XK_Left) { 1779 next_index = data->ev_i; 1780 } else { 1781 next_index = 0; 1782 } 1783 } 1784 data->focused_control = data->dyn_controls[next_index]; 1785 data->focused_control->selected = true; 1786 break; 1787 } 1788 } 1789 } 1790 break; 1791 } 1792 } 1793 1794 if (data->draw) { 1795 X11Toolkit_DrawWindow(data); 1796 } 1797} 1798 1799void X11Toolkit_DoWindowEventLoop(SDL_ToolkitWindowX11 *data) { 1800 while (!data->close) { 1801 XEvent e; 1802 1803 /* Process settings events */ 1804 X11_XPeekEvent(data->display, &e); 1805 if (data->xsettings) { 1806 xsettings_client_process_event(data->xsettings, &e); 1807 } 1808 1809 /* Do actual event loop */ 1810 X11_XIfEvent(data->display, &e, X11Toolkit_EventTest, (XPointer)data); 1811 X11Toolkit_ProcessWindowEvents(data, &e); 1812 } 1813} 1814 1815 1816void X11Toolkit_ResizeWindow(SDL_ToolkitWindowX11 *data, int w, int h) { 1817 if (!data->pixmap) { 1818 data->window_width = w; 1819 data->window_height = h; 1820 } else { 1821 data->window_width = SDL_lroundf((w/data->iscale) * data->scale); 1822 data->window_height = SDL_lroundf((h/data->iscale) * data->scale); 1823 data->pixmap_width = w; 1824 data->pixmap_height = h; 1825 X11_XFreePixmap(data->display, data->drawable); 1826 X11Toolkit_InitWindowPixmap(data); 1827 } 1828 1829 X11_XResizeWindow(data->display, data->window, data->window_width, data->window_height); 1830} 1831 1832static void X11Toolkit_DestroyIconControl(SDL_ToolkitControlX11 *control) { 1833 SDL_ToolkitIconControlX11 *icon_control; 1834 1835 icon_control = (SDL_ToolkitIconControlX11 *)control; 1836 X11_XFreeFont(control->window->display, icon_control->icon_char_font); 1837 SDL_free(control); 1838} 1839 1840static void X11Toolkit_DrawIconControl(SDL_ToolkitControlX11 *control) { 1841 SDL_ToolkitIconControlX11 *icon_control; 1842 1843 icon_control = (SDL_ToolkitIconControlX11 *)control; 1844 control->rect.w -= 2 * control->window->iscale; 1845 control->rect.h -= 2 * control->window->iscale; 1846 X11_XSetForeground(control->window->display, control->window->ctx, icon_control->xcolor_bg_shadow.pixel); 1847 X11_XFillArc(control->window->display, control->window->drawable, control->window->ctx, control->rect.x + (2 * control->window->iscale), control->rect.y + (2* control->window->iscale), control->rect.w, control->rect.h, 0, 360 * 64); 1848 1849 switch (icon_control->flags & (SDL_MESSAGEBOX_ERROR | SDL_MESSAGEBOX_WARNING | SDL_MESSAGEBOX_INFORMATION)) { 1850 case SDL_MESSAGEBOX_ERROR: 1851 X11_XSetForeground(control->window->display, control->window->ctx, icon_control->xcolor_red_darker.pixel); 1852 X11_XFillArc(control->window->display, control->window->drawable, control->window->ctx, control->rect.x, control->rect.y, control->rect.w, control->rect.h, 0, 360 * 64); 1853 X11_XSetForeground(control->window->display, control->window->ctx, icon_control->xcolor_red.pixel); 1854 X11_XFillArc(control->window->display, control->window->drawable, control->window->ctx, control->rect.x+(1* control->window->iscale), control->rect.y+(1* control->window->iscale), control->rect.w-(2* control->window->iscale), control->rect.h-(2* control->window->iscale), 0, 360 * 64); 1855 X11_XSetForeground(control->window->display, control->window->ctx, icon_control->xcolor_white.pixel); 1856 break; 1857 case SDL_MESSAGEBOX_WARNING: 1858 X11_XSetForeground(control->window->display, control->window->ctx, icon_control->xcolor_black.pixel); 1859 X11_XFillArc(control->window->display, control->window->drawable, control->window->ctx, control->rect.x, control->rect.y, control->rect.w, control->rect.h, 0, 360 * 64); 1860 X11_XSetForeground(control->window->display, control->window->ctx, icon_control->xcolor_yellow.pixel); 1861 X11_XFillArc(control->window->display, control->window->drawable, control->window->ctx, control->rect.x+(1* control->window->iscale), control->rect.y+(1* control->window->iscale), control->rect.w-(2* control->window->iscale), control->rect.h-(2* control->window->iscale), 0, 360 * 64); 1862 X11_XSetForeground(control->window->display, control->window->ctx, icon_control->xcolor_black.pixel); 1863 break; 1864 case SDL_MESSAGEBOX_INFORMATION: 1865 X11_XSetForeground(control->window->display, control->window->ctx, icon_control->xcolor_white.pixel); 1866 X11_XFillArc(control->window->display, control->window->drawable, control->window->ctx, control->rect.x, control->rect.y, control->rect.w, control->rect.h, 0, 360 * 64); 1867 X11_XSetForeground(control->window->display, control->window->ctx, icon_control->xcolor_blue.pixel); 1868 X11_XFillArc(control->window->display, control->window->drawable, control->window->ctx, control->rect.x+(1* control->window->iscale), control->rect.y+(1* control->window->iscale), control->rect.w-(2* control->window->iscale), control->rect.h-(2* control->window->iscale), 0, 360 * 64); 1869 X11_XSetForeground(control->window->display, control->window->ctx, icon_control->xcolor_white.pixel); 1870 break; 1871 } 1872 X11_XSetFont(control->window->display, control->window->ctx, icon_control->icon_char_font->fid); 1873 X11_XDrawString(control->window->display, control->window->drawable, control->window->ctx, control->rect.x + icon_control->icon_char_x, control->rect.y + icon_control->icon_char_y, &icon_control->icon_char, 1); 1874 if (!control->window->utf8) { 1875 X11_XSetFont(control->window->display, control->window->ctx, control->window->font_struct->fid); 1876 } 1877 1878 control->rect.w += 2 * control->window->iscale; 1879 control->rect.h += 2 * control->window->iscale; 1880} 1881 1882static void X11Toolkit_CalculateIconControl(SDL_ToolkitControlX11 *base_control) { 1883 SDL_ToolkitIconControlX11 *control; 1884 int icon_char_w; 1885 int icon_wh; 1886 1887 control = (SDL_ToolkitIconControlX11 *)base_control; 1888 X11Toolkit_GetTextWidthHeightForFont(control->icon_char_font, &control->icon_char, 1, &icon_char_w, &control->icon_char_h, &control->icon_char_a, NULL); 1889 base_control->rect.w = icon_char_w; 1890 base_control->rect.h = control->icon_char_h; 1891 icon_wh = SDL_max(icon_char_w, control->icon_char_h) + SDL_TOOLKIT_X11_ELEMENT_PADDING * 2 * base_control->window->iscale; 1892 base_control->rect.w = icon_wh; 1893 base_control->rect.h = icon_wh; 1894 base_control->rect.y = 0; 1895 base_control->rect.x = 0; 1896 control->icon_char_y = control->icon_char_a + (base_control->rect.h - control->icon_char_h)/2; 1897 control->icon_char_x = (base_control->rect.w - icon_char_w)/2; 1898 base_control->rect.w += 2 * base_control->window->iscale; 1899 base_control->rect.h += 2 * base_control->window->iscale; 1900} 1901 1902static void X11Toolkit_OnIconControlScaleChange(SDL_ToolkitControlX11 *base_control) { 1903 SDL_ToolkitIconControlX11 *control; 1904 char *font; 1905 1906 control = (SDL_ToolkitIconControlX11 *)base_control; 1907 X11_XFreeFont(base_control->window->display, control->icon_char_font); 1908 SDL_asprintf(&font, g_IconFont, G_ICONFONT_SIZE * base_control->window->iscale); 1909 control->icon_char_font = X11_XLoadQueryFont(base_control->window->display, font); 1910 SDL_free(font); 1911 if (!control->icon_char_font) { 1912 SDL_asprintf(&font, g_ToolkitFontLatin1, G_TOOLKITFONT_SIZE * base_control->window->iscale); 1913 control->icon_char_font = X11_XLoadQueryFont(base_control->window->display, font); 1914 SDL_free(font); 1915 } 1916} 1917 1918SDL_ToolkitControlX11 *X11Toolkit_CreateIconControl(SDL_ToolkitWindowX11 *window, SDL_MessageBoxFlags flags) { 1919 SDL_ToolkitIconControlX11 *control; 1920 SDL_ToolkitControlX11 *base_control; 1921 char *font; 1922 1923 /* Create control struct */ 1924 control = (SDL_ToolkitIconControlX11 *)SDL_malloc(sizeof(SDL_ToolkitIconControlX11)); 1925 base_control = (SDL_ToolkitControlX11 *)control; 1926 if (!control) { 1927 SDL_SetError("Unable to allocate icon control structure"); 1928 return NULL; 1929 } 1930 1931 /* Fill out struct */ 1932 base_control->window = window; 1933 base_control->func_draw = X11Toolkit_DrawIconControl; 1934 base_control->func_free = X11Toolkit_DestroyIconControl; 1935 base_control->func_on_state_change = NULL; 1936 base_control->func_calc_size = X11Toolkit_CalculateIconControl; 1937 base_control->func_on_scale_change = X11Toolkit_OnIconControlScaleChange; 1938 base_control->state = SDL_TOOLKIT_CONTROL_STATE_X11_NORMAL; 1939 base_control->selected = false; 1940 base_control->dynamic = false; 1941 base_control->is_default_enter = false; 1942 base_control->is_default_esc = false; 1943 control->flags = flags; 1944 1945 /* Load font */ 1946 SDL_asprintf(&font, g_IconFont, G_ICONFONT_SIZE * window->iscale); 1947 control->icon_char_font = X11_XLoadQueryFont(window->display, font); 1948 SDL_free(font); 1949 if (!control->icon_char_font) { 1950 SDL_asprintf(&font, g_ToolkitFontLatin1, G_TOOLKITFONT_SIZE * window->iscale); 1951 control->icon_char_font = X11_XLoadQueryFont(window->display, font); 1952 SDL_free(font); 1953 if (!control->icon_char_font) { 1954 SDL_free(control); 1955 return NULL; 1956 } 1957 } 1958 1959 /* Set colors */ 1960 switch (flags & (SDL_MESSAGEBOX_ERROR | SDL_MESSAGEBOX_WARNING | SDL_MESSAGEBOX_INFORMATION)) { 1961 case SDL_MESSAGEBOX_ERROR: 1962 control->icon_char = 'X'; 1963 control->xcolor_white.flags = DoRed|DoGreen|DoBlue; 1964 control->xcolor_white.red = 65535; 1965 control->xcolor_white.green = 65535; 1966 control->xcolor_white.blue = 65535; 1967 control->xcolor_red.flags = DoRed|DoGreen|DoBlue; 1968 control->xcolor_red.red = 65535; 1969 control->xcolor_red.green = 0; 1970 control->xcolor_red.blue = 0; 1971 control->xcolor_red_darker.flags = DoRed|DoGreen|DoBlue; 1972 control->xcolor_red_darker.red = 40535; 1973 control->xcolor_red_darker.green = 0; 1974 control->xcolor_red_darker.blue = 0; 1975 X11_XAllocColor(window->display, window->cmap, &control->xcolor_white); 1976 X11_XAllocColor(window->display, window->cmap, &control->xcolor_red); 1977 X11_XAllocColor(window->display, window->cmap, &control->xcolor_red_darker); 1978 break; 1979 case SDL_MESSAGEBOX_WARNING: 1980 control->icon_char = '!'; 1981 control->xcolor_black.flags = DoRed|DoGreen|DoBlue; 1982 control->xcolor_black.red = 0; 1983 control->xcolor_black.green = 0; 1984 control->xcolor_black.blue = 0; 1985 control->xcolor_yellow.flags = DoRed|DoGreen|DoBlue; 1986 control->xcolor_yellow.red = 65535; 1987 control->xcolor_yellow.green = 65535; 1988 control->xcolor_yellow.blue = 0; 1989 X11_XAllocColor(window->display, window->cmap, &control->xcolor_black); 1990 X11_XAllocColor(window->display, window->cmap, &control->xcolor_yellow); 1991 break; 1992 case SDL_MESSAGEBOX_INFORMATION: 1993 control->icon_char = 'i'; 1994 control->xcolor_white.flags = DoRed|DoGreen|DoBlue; 1995 control->xcolor_white.red = 65535; 1996 control->xcolor_white.green = 65535; 1997 control->xcolor_white.blue = 65535; 1998 control->xcolor_blue.flags = DoRed|DoGreen|DoBlue; 1999 control->xcolor_blue.red = 0; 2000 control->xcolor_blue.green = 0; 2001 control->xcolor_blue.blue = 65535; 2002 X11_XAllocColor(window->display, window->cmap, &control->xcolor_white); 2003 X11_XAllocColor(window->display, window->cmap, &control->xcolor_blue); 2004 break; 2005 default: 2006 X11_XFreeFont(window->display, control->icon_char_font); 2007 SDL_free(control); 2008 return NULL; 2009 } 2010 control->xcolor_bg_shadow.flags = DoRed|DoGreen|DoBlue; 2011 if (window->xcolor[SDL_MESSAGEBOX_COLOR_BACKGROUND].red > 32896) { 2012 control->xcolor_bg_shadow.red = SDL_clamp(window->xcolor[SDL_MESSAGEBOX_COLOR_BACKGROUND].red - 12500, 0, 65535); 2013 } else if (window->xcolor[SDL_MESSAGEBOX_COLOR_BACKGROUND].red == 0) { 2014 control->xcolor_bg_shadow.red = SDL_clamp(window->xcolor[SDL_MESSAGEBOX_COLOR_BACKGROUND].red + 9000, 0, 65535); 2015 } else { 2016 control->xcolor_bg_shadow.red = SDL_clamp(window->xcolor[SDL_MESSAGEBOX_COLOR_BACKGROUND].red - 3000, 0, 65535); 2017 } 2018 2019 if (window->xcolor[SDL_MESSAGEBOX_COLOR_BACKGROUND].green > 32896) { 2020 control->xcolor_bg_shadow.green = SDL_clamp(window->xcolor[SDL_MESSAGEBOX_COLOR_BACKGROUND].green - 12500, 0, 65535); 2021 } else if (window->xcolor[SDL_MESSAGEBOX_COLOR_BACKGROUND].green == 0) { 2022 control->xcolor_bg_shadow.green = SDL_clamp(window->xcolor[SDL_MESSAGEBOX_COLOR_BACKGROUND].green + 9000, 0, 65535); 2023 } else { 2024 control->xcolor_bg_shadow.green = SDL_clamp(window->xcolor[SDL_MESSAGEBOX_COLOR_BACKGROUND].green - 3000, 0, 65535); 2025 } 2026 2027 if (window->xcolor[SDL_MESSAGEBOX_COLOR_BACKGROUND].blue > 32896) { 2028 control->xcolor_bg_shadow.blue = SDL_clamp(window->xcolor[SDL_MESSAGEBOX_COLOR_BACKGROUND].blue - 12500, 0, 65535); 2029 } else if (window->xcolor[SDL_MESSAGEBOX_COLOR_BACKGROUND].blue == 0) { 2030 control->xcolor_bg_shadow.blue = SDL_clamp(window->xcolor[SDL_MESSAGEBOX_COLOR_BACKGROUND].blue + 9000, 0, 65535); 2031 } else { 2032 control->xcolor_bg_shadow.blue = SDL_clamp(window->xcolor[SDL_MESSAGEBOX_COLOR_BACKGROUND].blue - 3000, 0, 65535); 2033 } 2034 X11_XAllocColor(window->display, window->cmap, &control->xcolor_bg_shadow); 2035 2036 /* Sizing and positioning */ 2037 X11Toolkit_CalculateIconControl(base_control); 2038 2039 X11Toolkit_AddControlToWindow(window, base_control); 2040 return base_control; 2041} 2042 2043bool X11Toolkit_NotifyControlOfSizeChange(SDL_ToolkitControlX11 *control) { 2044 if (control->func_calc_size) { 2045 control->func_calc_size(control); 2046 return true; 2047 } else { 2048 return false; 2049 } 2050} 2051 2052static void X11Toolkit_CalculateButtonControl(SDL_ToolkitControlX11 *control) { 2053 SDL_ToolkitButtonControlX11 *button_control; 2054 2055 button_control = (SDL_ToolkitButtonControlX11 *)control; 2056 X11Toolkit_GetTextElementsRect(button_control->text, &button_control->text_rect); 2057 if (control->do_size) { 2058 control->rect.w = SDL_TOOLKIT_X11_ELEMENT_PADDING_3 * 2 * control->window->iscale + button_control->text_rect.w; 2059 control->rect.h = SDL_TOOLKIT_X11_ELEMENT_PADDING_3 * 2 * control->window->iscale + button_control->text_rect.h; 2060 } 2061 button_control->text_rect.x = (control->rect.w - button_control->text_rect.w)/2; 2062 button_control->text_rect.y = (control->rect.h - button_control->text_rect.h)/2; 2063} 2064 2065 2066static void X11Toolkit_DrawButtonControl(SDL_ToolkitControlX11 *control) { 2067 SDL_ToolkitButtonControlX11 *button_control; 2068 2069 button_control = (SDL_ToolkitButtonControlX11 *)control; 2070 2071 X11_XSetForeground(control->window->display, control->window->ctx, control->window->xcolor[SDL_MESSAGEBOX_COLOR_TEXT].pixel); 2072 /* Draw bevel */ 2073 if (control->state == SDL_TOOLKIT_CONTROL_STATE_X11_PRESSED || control->state == SDL_TOOLKIT_CONTROL_STATE_X11_PRESSED_HELD) { 2074 X11_XSetForeground(control->window->display, control->window->ctx, control->window->xcolor_bevel_d.pixel); 2075 X11_XFillRectangle(control->window->display, control->window->drawable, control->window->ctx, 2076 control->rect.x, control->rect.y, 2077 control->rect.w, control->rect.h); 2078 2079 X11_XSetForeground(control->window->display, control->window->ctx, control->window->xcolor_bevel_l2.pixel); 2080 X11_XFillRectangle(control->window->display, control->window->drawable, control->window->ctx, 2081 control->rect.x, control->rect.y, 2082 control->rect.w - (1* control->window->iscale), control->rect.h - (1* control->window->iscale)); 2083 2084 X11_XSetForeground(control->window->display, control->window->ctx, control->window->xcolor_bevel_l1.pixel); 2085 X11_XFillRectangle(control->window->display, control->window->drawable, control->window->ctx, 2086 control->rect.x + 1 * control->window->iscale, control->rect.y + 1 * control->window->iscale, 2087 control->rect.w - 3 * control->window->iscale, control->rect.h - 2 * control->window->iscale); 2088 2089 X11_XSetForeground(control->window->display, control->window->ctx, control->window->xcolor[SDL_MESSAGEBOX_COLOR_BUTTON_BORDER].pixel); 2090 X11_XFillRectangle(control->window->display, control->window->drawable, control->window->ctx, 2091 control->rect.x + 1 * control->window->iscale, control->rect.y + 1 * control->window->iscale, 2092 control->rect.w - 3 * control->window->iscale, control->rect.h - 3 * control->window->iscale); 2093 2094 X11_XSetForeground(control->window->display, control->window->ctx, control->window->xcolor_pressed.pixel); 2095 X11_XFillRectangle(control->window->display, control->window->drawable, control->window->ctx, 2096 control->rect.x + 2 * control->window->iscale, control->rect.y + 2 * control->window->iscale, 2097 control->rect.w - 4 * control->window->iscale, control->rect.h - 4 * control->window->iscale); 2098 } else { 2099 if (control->selected) { 2100 X11_XSetForeground(control->window->display, control->window->ctx, control->window->xcolor_bevel_d.pixel); 2101 X11_XFillRectangle(control->window->display, control->window->drawable, control->window->ctx, 2102 control->rect.x, control->rect.y, 2103 control->rect.w, control->rect.h); 2104 2105 X11_XSetForeground(control->window->display, control->window->ctx, control->window->xcolor_bevel_l2.pixel); 2106 X11_XFillRectangle(control->window->display, control->window->drawable, control->window->ctx, 2107 control->rect.x + 1 * control->window->iscale, control->rect.y + 1 * control->window->iscale, 2108 control->rect.w - 3 * control->window->iscale, control->rect.h - 3 * control->window->iscale); 2109 2110 X11_XSetForeground(control->window->display, control->window->ctx, control->window->xcolor[SDL_MESSAGEBOX_COLOR_BUTTON_BORDER].pixel); 2111 X11_XFillRectangle(control->window->display, control->window->drawable, control->window->ctx, 2112 control->rect.x + 2 * control->window->iscale, control->rect.y + 2 * control->window->iscale, 2113 control->rect.w - 4 * control->window->iscale, control->rect.h - 4 * control->window->iscale); 2114 2115 X11_XSetForeground(control->window->display, control->window->ctx, control->window->xcolor_bevel_l1.pixel); 2116 X11_XFillRectangle(control->window->display, control->window->drawable, control->window->ctx, 2117 control->rect.x + 2 * control->window->iscale, control->rect.y + 2 * control->window->iscale, 2118 control->rect.w - 5 * control->window->iscale, control->rect.h - 5 * control->window->iscale); 2119 2120 X11_XSetForeground(control->window->display, control->window->ctx, (control->state == SDL_TOOLKIT_CONTROL_STATE_X11_HOVER) ? control->window->xcolor[SDL_MESSAGEBOX_COLOR_BUTTON_SELECTED].pixel : control->window->xcolor[SDL_MESSAGEBOX_COLOR_BUTTON_BACKGROUND].pixel); 2121 X11_XFillRectangle(control->window->display, control->window->drawable, control->window->ctx, 2122 control->rect.x + 3 * control->window->iscale, control->rect.y + 3 * control->window->iscale, 2123 control->rect.w - 6 * control->window->iscale, control->rect.h - 6 * control->window->iscale); 2124 } else { 2125 X11_XSetForeground(control->window->display, control->window->ctx, control->window->xcolor_bevel_d.pixel); 2126 X11_XFillRectangle(control->window->display, control->window->drawable, control->window->ctx, 2127 control->rect.x, control->rect.y, 2128 control->rect.w, control->rect.h); 2129 2130 X11_XSetForeground(control->window->display, control->window->ctx, control->window->xcolor_bevel_l2.pixel); 2131 X11_XFillRectangle(control->window->display, control->window->drawable, control->window->ctx, 2132 control->rect.x, control->rect.y, 2133 control->rect.w - 1 * control->window->iscale, control->rect.h - 1 * control->window->iscale); 2134 2135 X11_XSetForeground(control->window->display, control->window->ctx, control->window->xcolor[SDL_MESSAGEBOX_COLOR_BUTTON_BORDER].pixel); 2136 X11_XFillRectangle(control->window->display, control->window->drawable, control->window->ctx, 2137 control->rect.x + 1 * control->window->iscale, control->rect.y + 1 * control->window->iscale, 2138 control->rect.w - 2 * control->window->iscale, control->rect.h - 2 * control->window->iscale); 2139 2140 X11_XSetForeground(control->window->display, control->window->ctx, control->window->xcolor_bevel_l1.pixel); 2141 X11_XFillRectangle(control->window->display, control->window->drawable, control->window->ctx, 2142 control->rect.x + 1 * control->window->iscale, control->rect.y + 1 * control->window->iscale, 2143 control->rect.w - 3 * control->window->iscale, control->rect.h - 3 * control->window->iscale); 2144 2145 X11_XSetForeground(control->window->display, control->window->ctx, (control->state == SDL_TOOLKIT_CONTROL_STATE_X11_HOVER) ? control->window->xcolor[SDL_MESSAGEBOX_COLOR_BUTTON_SELECTED].pixel : control->window->xcolor[SDL_MESSAGEBOX_COLOR_BUTTON_BACKGROUND].pixel); 2146 X11_XFillRectangle(control->window->display, control->window->drawable, control->window->ctx, 2147 control->rect.x + 2 * control->window->iscale, control->rect.y + 2 * control->window->iscale, 2148 control->rect.w - 4 * control->window->iscale, control->rect.h - 4 * control->window->iscale); 2149 } 2150 } 2151 2152 X11_XSetForeground(control->window->display, control->window->ctx, control->window->xcolor[SDL_MESSAGEBOX_COLOR_TEXT].pixel); 2153 X11Toolkit_DrawTextElements(control->window, button_control->text, control->rect.x + button_control->text_rect.x, control->rect.y + button_control->text_rect.y); 2154} 2155 2156static void X11Toolkit_OnButtonControlStateChange(SDL_ToolkitControlX11 *control) { 2157 SDL_ToolkitButtonControlX11 *button_control; 2158 2159 button_control = (SDL_ToolkitButtonControlX11 *)control; 2160 if (button_control->cb && control->state == SDL_TOOLKIT_CONTROL_STATE_X11_PRESSED) { 2161 button_control->cb(control, button_control->cb_data); 2162 } 2163} 2164 2165static void X11Toolkit_DestroyButtonControl(SDL_ToolkitControlX11 *control) { 2166 SDL_ToolkitButtonControlX11 *button_control; 2167 2168 button_control = (SDL_ToolkitButtonControlX11 *)control; 2169 2170 X11Toolkit_FreeTextElements(button_control->text); 2171 2172 SDL_free(control); 2173} 2174 2175SDL_ToolkitControlX11 *X11Toolkit_CreateButtonControl(SDL_ToolkitWindowX11 *window, const SDL_MessageBoxButtonData *data) { 2176 SDL_ToolkitButtonControlX11 *control; 2177 SDL_ToolkitControlX11 *base_control; 2178 2179 control = (SDL_ToolkitButtonControlX11 *)SDL_malloc(sizeof(SDL_ToolkitButtonControlX11)); 2180 base_control = (SDL_ToolkitControlX11 *)control; 2181 if (!control) { 2182 SDL_SetError("Unable to allocate button control structure"); 2183 return NULL; 2184 } 2185 base_control->window = window; 2186 base_control->state = SDL_TOOLKIT_CONTROL_STATE_X11_NORMAL; 2187 base_control->func_calc_size = X11Toolkit_CalculateButtonControl; 2188 base_control->func_draw = X11Toolkit_DrawButtonControl; 2189 base_control->func_on_state_change = X11Toolkit_OnButtonControlStateChange; 2190 base_control->func_free = X11Toolkit_DestroyButtonControl; 2191 base_control->func_on_scale_change = NULL; 2192 base_control->state = SDL_TOOLKIT_CONTROL_STATE_X11_NORMAL; 2193 base_control->selected = false; 2194 base_control->dynamic = true; 2195 base_control->is_default_enter = false; 2196 base_control->is_default_esc = false; 2197 if (data->flags & SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT) { 2198 base_control->is_default_esc = true; 2199 } 2200 if (data->flags & SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT) { 2201 base_control->is_default_enter = true; 2202 base_control->selected = true; 2203 } 2204 control->cb = NULL; 2205 control->data = data; 2206#ifdef HAVE_FRIBIDI_H 2207 control->text = X11Toolkit_MakeTextElements(base_control->window, (char *)control->data->text, SDL_strlen(control->data->text), NULL); 2208#else 2209 control->text = X11Toolkit_MakeTextElements(base_control->window, (char *)control->data->text, SDL_strlen(control->data->text)); 2210#endif 2211 X11Toolkit_ShapeTextElements(base_control->window, control->text); 2212 2213 base_control->do_size = true; 2214 X11Toolkit_CalculateButtonControl(base_control); 2215 base_control->do_size = false; 2216 2217 X11Toolkit_AddControlToWindow(window, base_control); 2218 return base_control; 2219} 2220 2221void X11Toolkit_RegisterCallbackForButtonControl(SDL_ToolkitControlX11 *control, void *data, void (*cb)(struct SDL_ToolkitControlX11 *, void *)) { 2222 SDL_ToolkitButtonControlX11 *button_control; 2223 2224 button_control = (SDL_ToolkitButtonControlX11 *)control; 2225 button_control->cb_data = data; 2226 button_control->cb = cb; 2227} 2228 2229const SDL_MessageBoxButtonData *X11Toolkit_GetButtonControlData(SDL_ToolkitControlX11 *control) { 2230 SDL_ToolkitButtonControlX11 *button_control; 2231 2232 button_control = (SDL_ToolkitButtonControlX11 *)control; 2233 return button_control->data; 2234} 2235 2236void X11Toolkit_DestroyWindow(SDL_ToolkitWindowX11 *data) { 2237 int i; 2238 2239 if (!data) { 2240 return; 2241 } 2242 2243#if SDL_GRAB 2244 if (data->mode == SDL_TOOLKIT_WINDOW_MODE_X11_MENU || data->mode== SDL_TOOLKIT_WINDOW_MODE_X11_TOOLTIP) { 2245 X11_XUngrabPointer(data->display, CurrentTime); 2246 X11_XUngrabKeyboard(data->display, CurrentTime); 2247 } 2248#endif 2249 2250 for (i = 0; i < data->controls_sz; i++) { 2251 if (data->controls[i]->func_free) { 2252 data->controls[i]->func_free(data->controls[i]); 2253 } 2254 } 2255 SDL_free(data->controls); 2256 SDL_free(data->dyn_controls); 2257 2258 if (data->popup_windows) { 2259 SDL_ListClear(&data->popup_windows); 2260 } 2261 2262 if (data->pixmap) { 2263 X11_XFreePixmap(data->display, data->drawable); 2264 } 2265 2266#ifndef NO_SHARED_MEMORY 2267 if (data->pixmap && data->shm) { 2268 X11_XShmDetach(data->display, &data->shm_info); 2269 if (!data->shm_pixmap) { 2270 XDestroyImage(data->image); 2271 } 2272 shmdt(data->shm_info.shmaddr); 2273 } 2274#endif 2275 2276#ifdef X_HAVE_UTF8_STRING 2277 if (data->font_set) { 2278 X11_XFreeFontSet(data->display, data->font_set); 2279 data->font_set = NULL; 2280 } 2281#endif 2282 2283 if (data->font_struct) { 2284 X11_XFreeFont(data->display, data->font_struct); 2285 data->font_struct = NULL; 2286 } 2287 2288#ifdef SDL_VIDEO_DRIVER_X11_XDBE 2289 if (SDL_X11_HAVE_XDBE && data->xdbe && !data->pixmap) { 2290 X11_XdbeDeallocateBackBufferName(data->display, data->buf); 2291 } 2292#endif 2293 2294 if (data->xsettings) { 2295 xsettings_client_destroy(data->xsettings); 2296 } 2297 2298 X11_XFreeGC(data->display, data->ctx); 2299 2300 if (data->display) { 2301 if (data->window != None) { 2302 X11_XWithdrawWindow(data->display, data->window, data->screen); 2303 X11_XDestroyWindow(data->display, data->window); 2304 data->window = None; 2305 } 2306 2307 if (data->display_close) { 2308 X11_XCloseDisplay(data->display); 2309 } 2310 data->display = NULL; 2311 } 2312 2313#if SDL_SET_LOCALE 2314 if (data->origlocale && (data->mode == SDL_TOOLKIT_WINDOW_MODE_X11_DIALOG)) { 2315 (void)setlocale(LC_ALL, data->origlocale); 2316 SDL_free(data->origlocale); 2317 } 2318#endif 2319 2320#ifdef HAVE_FRIBIDI_H 2321 SDL_FriBidi_Destroy(data->fribidi); 2322#endif 2323 2324#ifdef HAVE_LIBTHAI_H 2325 SDL_LibThai_Destroy(data->th); 2326#endif 2327 2328 SDL_free(data); 2329} 2330 2331static int X11Toolkit_CountLinesOfText(const char *text) 2332{ 2333 int result = 0; 2334 while (text && *text) { 2335 const char *lf = SDL_strchr(text, '\n'); 2336 result++; // even without an endline, this counts as a line. 2337 text = lf ? lf + 1 : NULL; 2338 } 2339 return result; 2340} 2341 2342static void X11Toolkit_DrawLabelControl(SDL_ToolkitControlX11 *control) { 2343 SDL_ToolkitLabelControlX11 *label_control; 2344 int i; 2345 2346 label_control = (SDL_ToolkitLabelControlX11 *)control; 2347 X11_XSetForeground(control->window->display, control->window->ctx, control->window->xcolor[SDL_MESSAGEBOX_COLOR_TEXT].pixel); 2348 for (i = 0; i < label_control->sz; i++) { 2349 X11Toolkit_DrawTextElements(control->window, label_control->lines[i].text, control->rect.x + label_control->lines[i].rect.x, control->rect.y + label_control->lines[i].rect.y); 2350 } 2351} 2352 2353static void X11Toolkit_DestroyLabelControl(SDL_ToolkitControlX11 *control) { 2354 SDL_ToolkitLabelControlX11 *label_control; 2355 int i; 2356 2357 label_control = (SDL_ToolkitLabelControlX11 *)control; 2358 for (i = 0; i < label_control->sz; i++) { 2359 X11Toolkit_FreeTextElements(label_control->lines[i].text); 2360 } 2361 SDL_free(label_control->lines); 2362 SDL_free(label_control); 2363} 2364 2365static void X11Toolkit_CalculateLabelControl(SDL_ToolkitControlX11 *base_control) { 2366 SDL_ToolkitLabelControlX11 *control; 2367 int i; 2368 2369 control = (SDL_ToolkitLabelControlX11 *)base_control; 2370 2371 if (base_control->do_size) { 2372 base_control->rect.w = 0; 2373 base_control->rect.h = 0; 2374 } 2375 2376 for (i = 0; i < control->sz; i++) { 2377 int font_h; 2378 2379 font_h = X11Toolkit_GetTextElementsRect(control->lines[i].text, &control->lines[i].rect); 2380 2381 if (base_control->do_size) { 2382 base_control->rect.w = SDL_max(base_control->rect.w, control->lines[i].rect.w); 2383 } 2384 2385 if (i > 0) { 2386 control->lines[i].rect.y = font_h + control->lines[i - 1].rect.y; 2387 } else { 2388 control->lines[i].rect.y = 0; 2389 } 2390 } 2391 2392#ifdef HAVE_FRIBIDI_H 2393 if (base_control->window->fribidi) { 2394 FriBidiParType first_ndn_dir; 2395 int last_ndn; 2396 2397 first_ndn_dir = FRIBIDI_PAR_LTR; 2398 for (i = 0; i < control->sz; i++) { 2399 if (control->lines[i].par != FRIBIDI_PAR_ON) { 2400 first_ndn_dir = control->lines[i].par; 2401 } 2402 } 2403 2404 last_ndn = -1; 2405 for (i = 0; i < control->sz; i++) { 2406 switch (control->lines[i].par) { 2407 case FRIBIDI_PAR_LTR: 2408 control->lines[i].rect.x = 0; 2409 last_ndn = i; 2410 break; 2411 case FRIBIDI_PAR_RTL: 2412 control->lines[i].rect.x = base_control->rect.w - control->lines[i].rect.w; 2413 last_ndn = i; 2414 break; 2415 default: 2416 if (last_ndn != -1) { 2417 if (control->lines[last_ndn].par == FRIBIDI_PAR_RTL) { 2418 control->lines[i].rect.x = base_control->rect.w - control->lines[i].rect.w; 2419 } else { 2420 control->lines[i].rect.x = 0; 2421 } 2422 } else { 2423 if (first_ndn_dir == FRIBIDI_PAR_RTL) { 2424 control->lines[i].rect.x = base_control->rect.w - control->lines[i].rect.w; 2425 } else { 2426 control->lines[i].rect.x = 0; 2427 } 2428 } 2429 } 2430 } 2431 } 2432#endif 2433 2434 if (base_control->do_size && control->sz) { 2435 base_control->rect.h = control->lines[control->sz - 1].rect.y + control->lines[control->sz - 1].rect.h; 2436 } 2437} 2438 2439SDL_ToolkitControlX11 *X11Toolkit_CreateLabelControl(SDL_ToolkitWindowX11 *window, char *utf8) { 2440 SDL_ToolkitLabelControlX11 *control; 2441 SDL_ToolkitControlX11 *base_control; 2442 int i; 2443 2444 if (!utf8) { 2445 return NULL; 2446 } 2447 2448 if (!SDL_strcmp(utf8, "")) { 2449 return NULL; 2450 } 2451 control = (SDL_ToolkitLabelControlX11 *)SDL_malloc(sizeof(SDL_ToolkitLabelControlX11)); 2452 base_control = (SDL_ToolkitControlX11 *)control; 2453 if (!control) { 2454 SDL_SetError("Unable to allocate label control structure"); 2455 return NULL; 2456 } 2457 base_control->window = window; 2458 base_control->func_draw = X11Toolkit_DrawLabelControl; 2459 base_control->func_on_state_change = NULL; 2460 base_control->func_calc_size = X11Toolkit_CalculateLabelControl; 2461 base_control->func_free = X11Toolkit_DestroyLabelControl; 2462 base_control->func_on_scale_change = NULL; 2463 base_control->state = SDL_TOOLKIT_CONTROL_STATE_X11_NORMAL; 2464 base_control->selected = false; 2465 base_control->dynamic = false; 2466 base_control->rect.w = 0; 2467 base_control->rect.h = 0; 2468 base_control->is_default_enter = false; 2469 base_control->is_default_esc = false; 2470 2471 control->sz = X11Toolkit_CountLinesOfText(utf8); 2472 control->lines = SDL_calloc(control->sz, sizeof(SDL_ToolkitLabelControlLineX11)); 2473 for (i = 0; i < control->sz; i++) { 2474 const char *lf = SDL_strchr(utf8, '\n'); 2475 const int length = lf ? (lf - utf8) : SDL_strlen(utf8); 2476 int sz; 2477 2478 sz = length; 2479 if (lf && (lf > utf8) && (lf[-1] == '\r')) { 2480 sz--; 2481 } 2482 2483#ifdef HAVE_FRIBIDI_H 2484 control->lines[i].text = X11Toolkit_MakeTextElements(base_control->window, (char *)utf8, sz, &control->lines[i].par); 2485#else 2486 control->lines[i].text = X11Toolkit_MakeTextElements(base_control->window, (char *)utf8, sz); 2487#endif 2488 X11Toolkit_ShapeTextElements(base_control->window, control->lines[i].text); 2489 2490 utf8 += length + 1; 2491 if (!lf) { 2492 break; 2493 } 2494 } 2495 2496 base_control->do_size = true; 2497 X11Toolkit_CalculateLabelControl(base_control); 2498 base_control->do_size = false; 2499 X11Toolkit_AddControlToWindow(window, base_control); 2500 2501 return base_control; 2502} 2503 2504int X11Toolkit_GetLabelControlFirstLineHeight(SDL_ToolkitControlX11 *control) { 2505 SDL_ToolkitLabelControlX11 *label_control; 2506 2507 label_control = (SDL_ToolkitLabelControlX11 *)control; 2508 2509 return label_control->lines[0].rect.h; 2510} 2511 2512void X11Toolkit_SignalWindowClose(SDL_ToolkitWindowX11 *data) { 2513 data->close = true; 2514} 2515 2516#endif // SDL_VIDEO_DRIVER_X11 2517[FILE END](C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.