Atlas - SDL_x11toolkit.c

Home / ext / SDL / src / video / x11 Lines: 3 | Size: 102613 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)]
[FILE BEGIN]
1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2025 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_memset(utf8, 0, 5); 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(&current_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 return NULL; 980 } 981 (void)setlocale(LC_ALL, ""); 982 } 983 } 984#endif 985 986 window->parent_device = NULL; 987 if (create_new_display) { 988 window->display = X11_XOpenDisplay(NULL); 989 window->display_close = true; 990 if (!window->display) { 991 ErrorFreeRetNull("Couldn't open X11 display", window); 992 } 993 } else { 994 if (parent) { 995 window->parent_device = SDL_GetVideoDevice(); 996 window->display = window->parent_device->internal->display; 997 window->display_close = false; 998 } else if (tkparent) { 999 window->display = tkparent->display; 1000 window->display_close = false; 1001 } else { 1002 window->display = X11_XOpenDisplay(NULL); 1003 window->display_close = true; 1004 if (!window->display) { 1005 ErrorFreeRetNull("Couldn't open X11 display", window); 1006 } 1007 } 1008 } 1009 1010#ifdef SDL_VIDEO_DRIVER_X11_XRANDR 1011 int xrandr_event_base, xrandr_error_base; 1012 window->xrandr = X11_XRRQueryExtension(window->display, &xrandr_event_base, &xrandr_error_base); 1013#endif 1014 1015#ifndef NO_SHARED_MEMORY 1016 window->shm_pixmap = False; 1017 window->shm = X11_XShmQueryExtension(window->display) ? SDL_X11_HAVE_SHM : false; 1018 if (window->shm) { 1019 int major; 1020 int minor; 1021 1022 X11_XShmQueryVersion(window->display, &major, &minor, &window->shm_pixmap); 1023 if (window->shm_pixmap) { 1024 if (X11_XShmPixmapFormat(window->display) != ZPixmap) { 1025 window->shm_pixmap = False; 1026 } 1027 } 1028 } 1029#endif 1030 1031 /* Scale/Xsettings */ 1032 window->pixmap = false; 1033 window->xsettings_first_time = true; 1034 window->xsettings = xsettings_client_new(window->display, DefaultScreen(window->display), X11Toolkit_SettingsNotify, NULL, window); 1035 window->xsettings_first_time = false; 1036 window->scale = X11_GetGlobalContentScale(window->display, window->xsettings); 1037 if (window->scale < 1) { 1038 window->scale = 1; 1039 } 1040 window->iscale = (int)SDL_ceilf(window->scale); 1041 if (SDL_roundf(window->scale) == window->scale) { 1042 window->scale = 0; 1043 } 1044 1045 /* Fonts */ 1046 X11Toolkit_InitWindowFonts(window); 1047 1048 /* Color hints */ 1049#ifdef SDL_USE_LIBDBUS 1050 theme = SDL_SYSTEM_THEME_LIGHT; 1051 if (SDL_SystemTheme_Init()) { 1052 theme = SDL_SystemTheme_Get(); 1053 } 1054#endif 1055 1056 if (!colorhints) { 1057#ifdef SDL_USE_LIBDBUS 1058 switch (theme) { 1059 case SDL_SYSTEM_THEME_DARK: 1060 colorhints = g_default_colors_dark; 1061 break; 1062#if 0 1063 case SDL_SYSTEM_THEME_LIGHT_HIGH_CONTRAST: 1064 colorhints = g_default_colors_light_high_contrast; 1065 break; 1066 case SDL_SYSTEM_THEME_DARK_HIGH_CONTRAST: 1067 colorhints = g_default_colors_dark_high_contrast; 1068 break; 1069#endif 1070 default: 1071 colorhints = g_default_colors; 1072 } 1073#else 1074 colorhints = g_default_colors; 1075#endif 1076 } 1077 window->color_hints = colorhints; 1078 1079 /* Convert colors to 16 bpc XColor format */ 1080 for (i = 0; i < SDL_MESSAGEBOX_COLOR_COUNT; i++) { 1081 window->xcolor[i].flags = DoRed|DoGreen|DoBlue; 1082 window->xcolor[i].red = colorhints[i].r * 257; 1083 window->xcolor[i].green = colorhints[i].g * 257; 1084 window->xcolor[i].blue = colorhints[i].b * 257; 1085 } 1086 1087 /* Generate bevel and pressed colors */ 1088 window->xcolor_bevel_l1.flags = DoRed|DoGreen|DoBlue; 1089 window->xcolor_bevel_l1.red = SDL_clamp(window->xcolor[SDL_MESSAGEBOX_COLOR_BUTTON_BORDER].red + 12500, 0, 65535); 1090 window->xcolor_bevel_l1.green = SDL_clamp(window->xcolor[SDL_MESSAGEBOX_COLOR_BUTTON_BORDER].green + 12500, 0, 65535); 1091 window->xcolor_bevel_l1.blue = SDL_clamp(window->xcolor[SDL_MESSAGEBOX_COLOR_BUTTON_BORDER].blue + 12500, 0, 65535); 1092 1093 window->xcolor_bevel_l2.flags = DoRed|DoGreen|DoBlue; 1094 window->xcolor_bevel_l2.red = SDL_clamp(window->xcolor[SDL_MESSAGEBOX_COLOR_BUTTON_BORDER].red + 32500, 0, 65535); 1095 window->xcolor_bevel_l2.green = SDL_clamp(window->xcolor[SDL_MESSAGEBOX_COLOR_BUTTON_BORDER].green + 32500, 0, 65535); 1096 window->xcolor_bevel_l2.blue = SDL_clamp(window->xcolor[SDL_MESSAGEBOX_COLOR_BUTTON_BORDER].blue + 32500, 0, 65535); 1097 1098 window->xcolor_bevel_d.flags = DoRed|DoGreen|DoBlue; 1099 window->xcolor_bevel_d.red = SDL_clamp(window->xcolor[SDL_MESSAGEBOX_COLOR_BUTTON_BORDER].red - 22500, 0, 65535); 1100 window->xcolor_bevel_d.green = SDL_clamp(window->xcolor[SDL_MESSAGEBOX_COLOR_BUTTON_BORDER].green - 22500, 0, 65535); 1101 window->xcolor_bevel_d.blue = SDL_clamp(window->xcolor[SDL_MESSAGEBOX_COLOR_BUTTON_BORDER].blue - 22500, 0, 65535); 1102 1103 window->xcolor_pressed.flags = DoRed|DoGreen|DoBlue; 1104 window->xcolor_pressed.red = SDL_clamp(window->xcolor[SDL_MESSAGEBOX_COLOR_BUTTON_BACKGROUND].red - 12500, 0, 65535); 1105 window->xcolor_pressed.green = SDL_clamp(window->xcolor[SDL_MESSAGEBOX_COLOR_BUTTON_BACKGROUND].green - 12500, 0, 65535); 1106 window->xcolor_pressed.blue = SDL_clamp(window->xcolor[SDL_MESSAGEBOX_COLOR_BUTTON_BACKGROUND].blue - 12500, 0, 65535); 1107 1108 window->xcolor_disabled_text.flags = DoRed|DoGreen|DoBlue; 1109 window->xcolor_disabled_text.red = SDL_clamp(window->xcolor[SDL_MESSAGEBOX_COLOR_TEXT].red + 19500, 0, 65535); 1110 window->xcolor_disabled_text.green = SDL_clamp(window->xcolor[SDL_MESSAGEBOX_COLOR_TEXT].green + 19500, 0, 65535); 1111 window->xcolor_disabled_text.blue = SDL_clamp(window->xcolor[SDL_MESSAGEBOX_COLOR_TEXT].blue + 19500, 0, 65535); 1112 1113 /* Screen */ 1114 window->parent = parent; 1115 if (parent) { 1116 SDL_DisplayData *displaydata = SDL_GetDisplayDriverDataForWindow(parent); 1117 window->screen = displaydata->screen; 1118 } else { 1119 window->screen = DefaultScreen(window->display); 1120 } 1121 1122 /* Visuals */ 1123 if (mode == SDL_TOOLKIT_WINDOW_MODE_X11_CHILD) { 1124 window->visual = parent->internal->visual; 1125 window->cmap = parent->internal->colormap; 1126 X11_GetVisualInfoFromVisual(window->display, window->visual, &window->vi); 1127 window->depth = window->vi.depth; 1128 } else { 1129 window->visual = DefaultVisual(window->display, window->screen); 1130 window->cmap = DefaultColormap(window->display, window->screen); 1131 window->depth = DefaultDepth(window->display, window->screen); 1132 X11_GetVisualInfoFromVisual(window->display, window->visual, &window->vi); 1133 } 1134 1135 /* Allocate colors */ 1136 for (i = 0; i < SDL_MESSAGEBOX_COLOR_COUNT; i++) { 1137 X11_XAllocColor(window->display, window->cmap, &window->xcolor[i]); 1138 } 1139 X11_XAllocColor(window->display, window->cmap, &window->xcolor_bevel_l1); 1140 X11_XAllocColor(window->display, window->cmap, &window->xcolor_bevel_l2); 1141 X11_XAllocColor(window->display, window->cmap, &window->xcolor_bevel_d); 1142 X11_XAllocColor(window->display, window->cmap, &window->xcolor_pressed); 1143 X11_XAllocColor(window->display, window->cmap, &window->xcolor_disabled_text); 1144 1145 /* Control list */ 1146 window->has_focus = false; 1147 window->controls = NULL; 1148 window->controls_sz = 0; 1149 window->dyn_controls_sz = 0; 1150 window->fiddled_control = NULL; 1151 window->dyn_controls = NULL; 1152 1153 /* Menu windows */ 1154 window->popup_windows = NULL; 1155 1156 /* BIDI engine */ 1157#ifdef HAVE_FRIBIDI_H 1158 window->fribidi = SDL_FriBidi_Create(); 1159#endif 1160 1161#ifdef HAVE_LIBTHAI_H 1162 window->th = SDL_LibThai_Create(); 1163#endif 1164 1165 /* Interface direction */ 1166 window->flip_interface = X11Toolkit_ShouldFlipUI(); 1167 1168 return window; 1169} 1170 1171static void X11Toolkit_AddControlToWindow(SDL_ToolkitWindowX11 *window, SDL_ToolkitControlX11 *control) { 1172 /* Add to controls list */ 1173 window->controls_sz++; 1174 if (window->controls_sz == 1) { 1175 window->controls = (struct SDL_ToolkitControlX11 **)SDL_malloc(sizeof(struct SDL_ToolkitControlX11 *)); 1176 } else { 1177 window->controls = (struct SDL_ToolkitControlX11 **)SDL_realloc(window->controls, sizeof(struct SDL_ToolkitControlX11 *) * window->controls_sz); 1178 } 1179 window->controls[window->controls_sz - 1] = control; 1180 1181 /* If dynamic, add it to the dynamic controls list too */ 1182 if (control->dynamic) { 1183 window->dyn_controls_sz++; 1184 if (window->dyn_controls_sz == 1) { 1185 window->dyn_controls = (struct SDL_ToolkitControlX11 **)SDL_malloc(sizeof(struct SDL_ToolkitControlX11 *)); 1186 } else { 1187 window->dyn_controls = (struct SDL_ToolkitControlX11 **)SDL_realloc(window->dyn_controls, sizeof(struct SDL_ToolkitControlX11 *) * window->dyn_controls_sz); 1188 } 1189 window->dyn_controls[window->dyn_controls_sz - 1] = control; 1190 } 1191 1192 /* If selected, set currently focused control to it */ 1193 if (control->selected) { 1194 window->focused_control = control; 1195 } 1196} 1197 1198bool X11Toolkit_CreateWindowRes(SDL_ToolkitWindowX11 *data, int w, int h, int cx, int cy, char *title) 1199{ 1200 int x, y; 1201 XSizeHints *sizehints; 1202 XSetWindowAttributes wnd_attr; 1203 Atom _NET_WM_WINDOW_TYPE, _NET_WM_WINDOW_TYPE_DIALOG, _NET_WM_WINDOW_TYPE_DROPDOWN_MENU, _NET_WM_WINDOW_TYPE_TOOLTIP; 1204 SDL_WindowData *windowdata = NULL; 1205 Display *display = data->display; 1206 XGCValues ctx_vals; 1207 Window root_win; 1208 Window parent_win; 1209 unsigned long gcflags = GCForeground | GCBackground; 1210 unsigned long valuemask; 1211#ifdef SDL_VIDEO_DRIVER_X11_XRANDR 1212#ifdef XRANDR_DISABLED_BY_DEFAULT 1213 const bool use_xrandr_by_default = false; 1214#else 1215 const bool use_xrandr_by_default = true; 1216#endif 1217#endif 1218 1219 if (data->scale == 0) { 1220 data->window_width = w; 1221 data->window_height = h; 1222 } else { 1223 data->window_width = SDL_lroundf((w/data->iscale) * data->scale); 1224 data->window_height = SDL_lroundf((h/data->iscale) * data->scale); 1225 data->pixmap_width = w; 1226 data->pixmap_height = h; 1227 data->pixmap = true; 1228 } 1229 1230 if (data->parent) { 1231 windowdata = data->parent->internal; 1232 } 1233 1234 valuemask = CWEventMask | CWColormap; 1235 data->event_mask = ExposureMask | 1236 ButtonPressMask | ButtonReleaseMask | KeyPressMask | KeyReleaseMask | 1237 StructureNotifyMask | FocusChangeMask | PointerMotionMask; 1238 wnd_attr.event_mask = data->event_mask; 1239 wnd_attr.colormap = data->cmap; 1240 if (data->mode == SDL_TOOLKIT_WINDOW_MODE_X11_MENU || data->mode== SDL_TOOLKIT_WINDOW_MODE_X11_TOOLTIP) { 1241 valuemask |= CWOverrideRedirect | CWSaveUnder; 1242 wnd_attr.save_under = True; 1243 wnd_attr.override_redirect = True; 1244 } 1245 root_win = RootWindow(display, data->screen); 1246 if (data->mode == SDL_TOOLKIT_WINDOW_MODE_X11_CHILD) { 1247 parent_win = windowdata->xwindow; 1248 } else { 1249 parent_win = root_win; 1250 } 1251 1252 data->window = X11_XCreateWindow( 1253 display, parent_win, 1254 0, 0, 1255 data->window_width, data->window_height, 1256 0, data->depth, InputOutput, data->visual, 1257 valuemask, &wnd_attr); 1258 if (data->window == None) { 1259 return SDL_SetError("Couldn't create X window"); 1260 } 1261 1262 if (windowdata && data->mode == SDL_TOOLKIT_WINDOW_MODE_X11_DIALOG) { 1263 Atom _NET_WM_STATE = X11_XInternAtom(display, "_NET_WM_STATE", False); 1264 Atom stateatoms[16]; 1265 size_t statecount = 0; 1266 // Set some message-boxy window states when attached to a parent window... 1267 // we skip the taskbar since this will pop to the front when the parent window is clicked in the taskbar, etc 1268 stateatoms[statecount++] = X11_XInternAtom(display, "_NET_WM_STATE_SKIP_TASKBAR", False); 1269 stateatoms[statecount++] = X11_XInternAtom(display, "_NET_WM_STATE_SKIP_PAGER", False); 1270 stateatoms[statecount++] = X11_XInternAtom(display, "_NET_WM_STATE_FOCUSED", False); 1271 stateatoms[statecount++] = X11_XInternAtom(display, "_NET_WM_STATE_MODAL", False); 1272 SDL_assert(statecount <= SDL_arraysize(stateatoms)); 1273 X11_XChangeProperty(display, data->window, _NET_WM_STATE, XA_ATOM, 32, 1274 PropModeReplace, (unsigned char *)stateatoms, statecount); 1275 } 1276 1277 if (windowdata && data->mode != SDL_TOOLKIT_WINDOW_MODE_X11_CHILD) { 1278 X11_XSetTransientForHint(display, data->window, windowdata->xwindow); 1279 } 1280 1281 if (data->tk_parent) { 1282 X11_XSetTransientForHint(display, data->window, data->tk_parent->window); 1283 } 1284 1285 SDL_X11_SetWindowTitle(display, data->window, title); 1286 1287 // Let the window manager the type of the window 1288 if (data->mode == SDL_TOOLKIT_WINDOW_MODE_X11_DIALOG) { 1289 _NET_WM_WINDOW_TYPE = X11_XInternAtom(display, "_NET_WM_WINDOW_TYPE", False); 1290 _NET_WM_WINDOW_TYPE_DIALOG = X11_XInternAtom(display, "_NET_WM_WINDOW_TYPE_DIALOG", False); 1291 X11_XChangeProperty(display, data->window, _NET_WM_WINDOW_TYPE, XA_ATOM, 32, 1292 PropModeReplace, 1293 (unsigned char *)&_NET_WM_WINDOW_TYPE_DIALOG, 1); 1294 } else if (data->mode == SDL_TOOLKIT_WINDOW_MODE_X11_MENU) { 1295 _NET_WM_WINDOW_TYPE = X11_XInternAtom(display, "_NET_WM_WINDOW_TYPE", False); 1296 _NET_WM_WINDOW_TYPE_DROPDOWN_MENU = X11_XInternAtom(display, "_NET_WM_WINDOW_TYPE_DROPDOWN_MENU", False); 1297 X11_XChangeProperty(display, data->window, _NET_WM_WINDOW_TYPE, XA_ATOM, 32, 1298 PropModeReplace, 1299 (unsigned char *)&_NET_WM_WINDOW_TYPE_DROPDOWN_MENU, 1); 1300 } else if (data->mode == SDL_TOOLKIT_WINDOW_MODE_X11_TOOLTIP) { 1301 _NET_WM_WINDOW_TYPE = X11_XInternAtom(display, "_NET_WM_WINDOW_TYPE", False); 1302 _NET_WM_WINDOW_TYPE_TOOLTIP = X11_XInternAtom(display, "_NET_WM_WINDOW_TYPE_TOOLTIP", False); 1303 X11_XChangeProperty(display, data->window, _NET_WM_WINDOW_TYPE, XA_ATOM, 32, 1304 PropModeReplace, 1305 (unsigned char *)&_NET_WM_WINDOW_TYPE_TOOLTIP, 1); 1306 } 1307 1308 // Allow the window to be deleted by the window manager 1309 data->wm_delete_message = X11_XInternAtom(display, "WM_DELETE_WINDOW", False); 1310 X11_XSetWMProtocols(display, data->window, &data->wm_delete_message, 1); 1311 data->wm_protocols = X11_XInternAtom(display, "WM_PROTOCOLS", False); 1312 1313 if (data->mode == SDL_TOOLKIT_WINDOW_MODE_X11_MENU || data->mode== SDL_TOOLKIT_WINDOW_MODE_X11_TOOLTIP) { 1314 x = cx; 1315 y = cy; 1316 goto MOVEWINDOW; 1317 } 1318 if (windowdata) { 1319 XWindowAttributes attrib; 1320 Window dummy; 1321 1322 X11_XGetWindowAttributes(display, windowdata->xwindow, &attrib); 1323 x = attrib.x + (attrib.width - data->window_width) / 2; 1324 y = attrib.y + (attrib.height - data->window_height) / 3; 1325 X11_XTranslateCoordinates(display, windowdata->xwindow, RootWindow(display, data->screen), x, y, &x, &y, &dummy); 1326 } else { 1327 const SDL_VideoDevice *dev = SDL_GetVideoDevice(); 1328 if (dev && dev->displays && dev->num_displays > 0) { 1329 const SDL_VideoDisplay *dpy = dev->displays[0]; 1330 const SDL_DisplayData *dpydata = dpy->internal; 1331 x = dpydata->x + ((dpy->current_mode->w - data->window_width) / 2); 1332 y = dpydata->y + ((dpy->current_mode->h - data->window_height) / 3); 1333 } 1334#ifdef SDL_VIDEO_DRIVER_X11_XRANDR 1335 else if (SDL_GetHintBoolean(SDL_HINT_VIDEO_X11_XRANDR, use_xrandr_by_default) && data->xrandr) { 1336 XRRScreenResources *screen_res; 1337 XRRCrtcInfo *crtc_info; 1338 RROutput default_out; 1339 1340 screen_res = X11_XRRGetScreenResourcesCurrent(display, root_win); 1341 if (!screen_res) { 1342 goto NOXRANDR; 1343 } 1344 1345 default_out = X11_XRRGetOutputPrimary(display, root_win); 1346 if (default_out != None) { 1347 XRROutputInfo *out_info; 1348 1349 out_info = X11_XRRGetOutputInfo(display, screen_res, default_out); 1350 if (out_info->connection != RR_Connected) { 1351 X11_XRRFreeOutputInfo(out_info); 1352 goto FIRSTOUTPUTXRANDR; 1353 } 1354 1355 if (out_info->crtc != None) { 1356 crtc_info = X11_XRRGetCrtcInfo(display, screen_res, out_info->crtc); 1357 } else if (out_info->ncrtc > 0) { 1358 crtc_info = X11_XRRGetCrtcInfo(display, screen_res, out_info->crtcs[0]); 1359 } else { 1360 crtc_info = NULL; 1361 } 1362 1363 if (crtc_info) { 1364 x = (crtc_info->width - data->window_width) / 2; 1365 y = (crtc_info->height - data->window_height) / 3; 1366 X11_XRRFreeOutputInfo(out_info); 1367 X11_XRRFreeCrtcInfo(crtc_info); 1368 X11_XRRFreeScreenResources(screen_res); 1369 } else { 1370 X11_XRRFreeOutputInfo(out_info); 1371 goto NOXRANDR; 1372 } 1373 } else { 1374 FIRSTOUTPUTXRANDR: 1375 if (screen_res->noutput > 0) { 1376 XRROutputInfo *out_info; 1377 1378 out_info = X11_XRRGetOutputInfo(display, screen_res, screen_res->outputs[0]); 1379 if (!out_info) { 1380 goto FIRSTCRTCXRANDR; 1381 } 1382 1383 if (out_info->crtc != None) { 1384 crtc_info = X11_XRRGetCrtcInfo(display, screen_res, out_info->crtc); 1385 } else if (out_info->ncrtc > 0) { 1386 crtc_info = X11_XRRGetCrtcInfo(display, screen_res, out_info->crtcs[0]); 1387 } else { 1388 crtc_info = NULL; 1389 } 1390 1391 if (!crtc_info) { 1392 X11_XRRFreeOutputInfo(out_info); 1393 goto FIRSTCRTCXRANDR; 1394 } 1395 1396 x = (crtc_info->width - data->window_width) / 2; 1397 y = (crtc_info->height - data->window_height) / 3; 1398 X11_XRRFreeOutputInfo(out_info); 1399 X11_XRRFreeCrtcInfo(crtc_info); 1400 X11_XRRFreeScreenResources(screen_res); 1401 goto MOVEWINDOW; 1402 } 1403 1404 FIRSTCRTCXRANDR: 1405 if (!screen_res->ncrtc) { 1406 X11_XRRFreeScreenResources(screen_res); 1407 goto NOXRANDR; 1408 } 1409 1410 crtc_info = X11_XRRGetCrtcInfo(display, screen_res, screen_res->crtcs[0]); 1411 if (crtc_info) { 1412 x = (crtc_info->width - data->window_width) / 2; 1413 y = (crtc_info->height - data->window_height) / 3; 1414 X11_XRRFreeCrtcInfo(crtc_info); 1415 X11_XRRFreeScreenResources(screen_res); 1416 } else { 1417 X11_XRRFreeScreenResources(screen_res); 1418 goto NOXRANDR; 1419 } 1420 } 1421 } 1422#endif 1423 else { 1424 // oh well. This will misposition on a multi-head setup. Init first next time. 1425 NOXRANDR: 1426 x = (DisplayWidth(display, data->screen) - data->window_width) / 2; 1427 y = (DisplayHeight(display, data->screen) - data->window_height) / 3; 1428 } 1429 } 1430 MOVEWINDOW: 1431 X11_XMoveWindow(display, data->window, x, y); 1432 data->window_x = x; 1433 data->window_y = y; 1434 1435 sizehints = X11_XAllocSizeHints(); 1436 if (sizehints) { 1437 sizehints->flags = USPosition | USSize | PMaxSize | PMinSize; 1438 sizehints->x = x; 1439 sizehints->y = y; 1440 sizehints->width = data->window_width; 1441 sizehints->height = data->window_height; 1442 1443 sizehints->min_width = sizehints->max_width = data->window_width; 1444 sizehints->min_height = sizehints->max_height = data->window_height; 1445 1446 X11_XSetWMNormalHints(display, data->window, sizehints); 1447 1448 X11_XFree(sizehints); 1449 } 1450 1451 X11_XMapRaised(display, data->window); 1452 1453 data->drawable = data->window; 1454#ifdef SDL_VIDEO_DRIVER_X11_XDBE 1455 // Initialise a back buffer for double buffering 1456 if (SDL_X11_HAVE_XDBE && !data->pixmap) { 1457 int xdbe_major, xdbe_minor; 1458 if (X11_XdbeQueryExtension(display, &xdbe_major, &xdbe_minor) != 0) { 1459 data->xdbe = true; 1460 data->buf = X11_XdbeAllocateBackBufferName(display, data->window, XdbeUndefined); 1461 data->drawable = data->buf; 1462 } else { 1463 data->xdbe = false; 1464 } 1465 } 1466#endif 1467 1468 X11Toolkit_InitWindowPixmap(data); 1469 1470 SDL_zero(ctx_vals); 1471 ctx_vals.foreground = data->xcolor[SDL_MESSAGEBOX_COLOR_BACKGROUND].pixel; 1472 ctx_vals.background = data->xcolor[SDL_MESSAGEBOX_COLOR_BACKGROUND].pixel; 1473 if (!data->utf8) { 1474 gcflags |= GCFont; 1475 ctx_vals.font = data->font_struct->fid; 1476 } 1477 data->ctx = X11_XCreateGC(data->display, data->drawable, gcflags, &ctx_vals); 1478 if (data->ctx == None) { 1479 return SDL_SetError("Couldn't create graphics context"); 1480 } 1481 1482 data->close = false; 1483 data->key_control_esc = data->key_control_enter = NULL; 1484 if (!data->pixmap) { 1485 data->ev_scale = data->ev_iscale = 1; 1486 } else { 1487 data->ev_scale = data->scale; 1488 data->ev_iscale = data->iscale; 1489 } 1490 1491#if SDL_GRAB 1492 if (data->mode == SDL_TOOLKIT_WINDOW_MODE_X11_MENU || data->mode== SDL_TOOLKIT_WINDOW_MODE_X11_TOOLTIP) { 1493 X11_XGrabPointer(display, data->window, False, ButtonPressMask | ButtonReleaseMask | PointerMotionMask, GrabModeAsync, GrabModeAsync, None, None, CurrentTime); 1494 X11_XGrabKeyboard(display, data->window, False, GrabModeAsync, GrabModeAsync, CurrentTime); 1495 } 1496#endif 1497 1498 return true; 1499} 1500 1501static void X11Toolkit_DrawWindow(SDL_ToolkitWindowX11 *data) { 1502 SDL_Rect rect; 1503 int i; 1504 1505#ifdef SDL_VIDEO_DRIVER_X11_XDBE 1506 if (SDL_X11_HAVE_XDBE && data->xdbe && !data->pixmap) { 1507 X11_XdbeBeginIdiom(data->display); 1508 } 1509#endif 1510 1511 X11_XSetForeground(data->display, data->ctx, data->xcolor[SDL_MESSAGEBOX_COLOR_BACKGROUND].pixel); 1512 if (data->pixmap) { 1513 X11_XFillRectangle(data->display, data->drawable, data->ctx, 0, 0, data->pixmap_width, data->pixmap_height); 1514 } else { 1515 X11_XFillRectangle(data->display, data->drawable, data->ctx, 0, 0, data->window_width, data->window_height); 1516 } 1517 1518 for (i = 0; i < data->controls_sz; i++) { 1519 SDL_ToolkitControlX11 *control; 1520 1521 control = data->controls[i]; 1522 if (control) { 1523 if (control->func_draw) { 1524 control->func_draw(control); 1525 } 1526 } 1527 } 1528 1529#ifdef SDL_VIDEO_DRIVER_X11_XDBE 1530 if (SDL_X11_HAVE_XDBE && data->xdbe && !data->pixmap) { 1531 XdbeSwapInfo swap_info; 1532 swap_info.swap_window = data->window; 1533 swap_info.swap_action = XdbeUndefined; 1534 X11_XdbeSwapBuffers(data->display, &swap_info, 1); 1535 X11_XdbeEndIdiom(data->display); 1536 } 1537#endif 1538 1539 if (data->pixmap) { 1540 SDL_Surface *scale_surface; 1541 1542 rect.x = rect.y = 0; 1543 rect.w = data->window_width; 1544 rect.h = data->window_height; 1545#ifndef NO_SHARED_MEMORY 1546 if (data->shm) { 1547 if (data->shm_pixmap) { 1548 X11_XFlush(data->display); 1549 X11_XSync(data->display, false); 1550 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); 1551 SDL_BlitSurfaceScaled(scale_surface, NULL, scale_surface, &rect, SDL_SCALEMODE_LINEAR); 1552 SDL_DestroySurface(scale_surface); 1553 X11_XCopyArea(data->display, data->drawable, data->window, data->ctx, 0, 0, data->window_width, data->window_height, 0, 0); 1554 } else { 1555 X11_XShmGetImage(data->display, data->drawable, data->image, 0, 0, AllPlanes); 1556 scale_surface = SDL_CreateSurfaceFrom(data->pixmap_width, data->pixmap_height, X11_GetPixelFormatFromVisualInfo(data->display, &data->vi), data->image->data, data->image->bytes_per_line); 1557 SDL_BlitSurfaceScaled(scale_surface, NULL, scale_surface, &rect, SDL_SCALEMODE_LINEAR); 1558 X11_XShmPutImage(data->display, data->window, data->ctx, data->image, 0, 0, 0, 0, data->window_width, data->window_height, False); 1559 } 1560 } else 1561#endif 1562 { 1563 XImage *image; 1564 1565 image = X11_XGetImage(data->display, data->drawable, 0, 0 , data->pixmap_width, data->pixmap_height, AllPlanes, ZPixmap); 1566 scale_surface = SDL_CreateSurfaceFrom(data->pixmap_width, data->pixmap_height, X11_GetPixelFormatFromVisualInfo(data->display, &data->vi), image->data, image->bytes_per_line); 1567 SDL_BlitSurfaceScaled(scale_surface, NULL, scale_surface, &rect, SDL_SCALEMODE_LINEAR); 1568 X11_XPutImage(data->display, data->window, data->ctx, image, 0, 0, 0, 0, data->window_width, data->window_height); 1569 1570 XDestroyImage(image); 1571 SDL_DestroySurface(scale_surface); 1572 } 1573 } 1574 1575 X11_XFlush(data->display); 1576} 1577 1578static SDL_ToolkitControlX11 *X11Toolkit_GetControlMouseIsOn(SDL_ToolkitWindowX11 *data, int x, int y) 1579{ 1580 int i; 1581 1582 for (i = 0; i < data->controls_sz; i++) { 1583 SDL_Rect *rect = &data->controls[i]->rect; 1584 if ((x >= rect->x) && 1585 (x <= (rect->x + rect->w)) && 1586 (y >= rect->y) && 1587 (y <= (rect->y + rect->h))) { 1588 return data->controls[i]; 1589 } 1590 } 1591 1592 return NULL; 1593} 1594 1595// NOLINTNEXTLINE(readability-non-const-parameter): cannot make XPointer a const pointer due to typedef 1596static Bool X11Toolkit_EventTest(Display *display, XEvent *event, XPointer arg) 1597{ 1598 SDL_ToolkitWindowX11 *data = (SDL_ToolkitWindowX11 *)arg; 1599 1600 if (event->xany.display != data->display) { 1601 return False; 1602 } 1603 1604 if (event->xany.window == data->window) { 1605 return True; 1606 } 1607 1608 return False; 1609} 1610 1611void X11Toolkit_ProcessWindowEvents(SDL_ToolkitWindowX11 *data, XEvent *e) { 1612 /* If X11_XFilterEvent returns True, then some input method has filtered the 1613 event, and the client should discard the event. */ 1614 if ((e->type != Expose) && X11_XFilterEvent(e, None)) { 1615 return; 1616 } 1617 1618 data->draw = false; 1619 data->e = e; 1620 1621 switch (e->type) { 1622 case Expose: 1623 data->draw = true; 1624 break; 1625 case ClientMessage: 1626 if (e->xclient.message_type == data->wm_protocols && 1627 e->xclient.format == 32 && 1628 e->xclient.data.l[0] == data->wm_delete_message) { 1629 data->close = true; 1630 } 1631 break; 1632 case FocusIn: 1633 data->has_focus = true; 1634 break; 1635 case FocusOut: 1636 data->has_focus = false; 1637 if (data->fiddled_control) { 1638 data->fiddled_control->selected = false; 1639 } 1640 data->fiddled_control = NULL; 1641 for (data->ev_i = 0; data->ev_i < data->controls_sz; data->ev_i++) { 1642 data->controls[data->ev_i]->state = SDL_TOOLKIT_CONTROL_STATE_X11_NORMAL; 1643 } 1644 break; 1645 case MotionNotify: 1646 if (data->has_focus) { 1647 data->previous_control = data->fiddled_control; 1648 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)); 1649 if (data->previous_control) { 1650 data->previous_control->state = SDL_TOOLKIT_CONTROL_STATE_X11_NORMAL; 1651 if (data->previous_control->func_on_state_change) { 1652 data->previous_control->func_on_state_change(data->previous_control); 1653 } 1654 data->draw = true; 1655 } 1656 if (data->fiddled_control) { 1657 if (data->fiddled_control->dynamic) { 1658 data->fiddled_control->state = SDL_TOOLKIT_CONTROL_STATE_X11_HOVER; 1659 if (data->fiddled_control->func_on_state_change) { 1660 data->fiddled_control->func_on_state_change(data->fiddled_control); 1661 } 1662 data->draw = true; 1663 } else { 1664 data->fiddled_control = NULL; 1665 } 1666 } 1667 } 1668 break; 1669 case ButtonPress: 1670 data->previous_control = data->fiddled_control; 1671 if (data->previous_control) { 1672 data->previous_control->state = SDL_TOOLKIT_CONTROL_STATE_X11_NORMAL; 1673 if (data->previous_control->func_on_state_change) { 1674 data->previous_control->func_on_state_change(data->previous_control); 1675 } 1676 data->draw = true; 1677 } 1678 if (e->xbutton.button == Button1) { 1679 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)); 1680 if (data->fiddled_control) { 1681 data->fiddled_control->state = SDL_TOOLKIT_CONTROL_STATE_X11_PRESSED_HELD; 1682 if (data->fiddled_control->func_on_state_change) { 1683 data->fiddled_control->func_on_state_change(data->fiddled_control); 1684 } 1685 data->draw = true; 1686 } 1687 } 1688 break; 1689 case ButtonRelease: 1690 if (data->mode == SDL_TOOLKIT_WINDOW_MODE_X11_MENU || data->mode== SDL_TOOLKIT_WINDOW_MODE_X11_TOOLTIP) { 1691 int cx; 1692 int cy; 1693 1694 cx = e->xbutton.x; 1695 cy = e->xbutton.y; 1696 1697 if (cy < 0 || cx < 0) { 1698 data->close = true; 1699 } 1700 1701 if (cy > data->window_height || cx > data->window_width) { 1702 data->close = true; 1703 } 1704 } 1705 1706 if ((e->xbutton.button == Button1) && (data->fiddled_control)) { 1707 SDL_ToolkitControlX11 *control; 1708 1709 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)); 1710 if (data->fiddled_control == control) { 1711 data->fiddled_control->state = SDL_TOOLKIT_CONTROL_STATE_X11_PRESSED; 1712 if (data->fiddled_control->func_on_state_change) { 1713 data->fiddled_control->func_on_state_change(data->fiddled_control); 1714 } 1715 data->fiddled_control->state = SDL_TOOLKIT_CONTROL_STATE_X11_NORMAL; 1716 data->draw = true; 1717 } 1718 } 1719 break; 1720 case KeyPress: 1721 data->last_key_pressed = X11_XLookupKeysym(&e->xkey, 0); 1722 1723 if (data->last_key_pressed == XK_Escape) { 1724 for (data->ev_i = 0; data->ev_i < data->controls_sz; data->ev_i++) { 1725 if(data->controls[data->ev_i]->is_default_esc) { 1726 data->controls[data->ev_i]->state = SDL_TOOLKIT_CONTROL_STATE_X11_PRESSED; 1727 data->draw = true; 1728 data->key_control_esc = data->controls[data->ev_i]; 1729 } 1730 } 1731 } else if ((data->last_key_pressed == XK_Return) || (data->last_key_pressed == XK_KP_Enter)) { 1732 for (data->ev_i = 0; data->ev_i < data->controls_sz; data->ev_i++) { 1733 if(data->controls[data->ev_i]->selected) { 1734 data->controls[data->ev_i]->state = SDL_TOOLKIT_CONTROL_STATE_X11_PRESSED; 1735 data->draw = true; 1736 data->key_control_enter = data->controls[data->ev_i]; 1737 } 1738 } 1739 } 1740 break; 1741 case KeyRelease: 1742 { 1743 KeySym key = X11_XLookupKeysym(&e->xkey, 0); 1744 1745 // If this is a key release for something we didn't get the key down for, then bail. 1746 if (key != data->last_key_pressed) { 1747 break; 1748 } 1749 1750 if (key == XK_Escape) { 1751 if (data->key_control_esc) { 1752 if (data->key_control_esc->func_on_state_change) { 1753 data->key_control_esc->func_on_state_change(data->key_control_esc); 1754 } 1755 } 1756 } else if ((key == XK_Return) || (key == XK_KP_Enter)) { 1757 if (data->key_control_enter) { 1758 if (data->key_control_enter->func_on_state_change) { 1759 data->key_control_enter->func_on_state_change(data->key_control_enter); 1760 } 1761 } 1762 } else if (key == XK_Tab || key == XK_Left || key == XK_Right) { 1763 if (data->focused_control) { 1764 data->focused_control->selected = false; 1765 } 1766 data->draw = true; 1767 for (data->ev_i = 0; data->ev_i < data->dyn_controls_sz; data->ev_i++) { 1768 if (data->dyn_controls[data->ev_i] == data->focused_control) { 1769 int next_index; 1770 1771 if (key == XK_Left) { 1772 next_index = data->ev_i - 1; 1773 } else { 1774 next_index = data->ev_i + 1; 1775 } 1776 if ((next_index >= data->dyn_controls_sz) || (next_index < 0)) { 1777 if (key == XK_Right || key == XK_Left) { 1778 next_index = data->ev_i; 1779 } else { 1780 next_index = 0; 1781 } 1782 } 1783 data->focused_control = data->dyn_controls[next_index]; 1784 data->focused_control->selected = true; 1785 break; 1786 } 1787 } 1788 } 1789 break; 1790 } 1791 } 1792 1793 if (data->draw) { 1794 X11Toolkit_DrawWindow(data); 1795 } 1796} 1797 1798void X11Toolkit_DoWindowEventLoop(SDL_ToolkitWindowX11 *data) { 1799 while (!data->close) { 1800 XEvent e; 1801 1802 /* Process settings events */ 1803 X11_XPeekEvent(data->display, &e); 1804 if (data->xsettings) { 1805 xsettings_client_process_event(data->xsettings, &e); 1806 } 1807 1808 /* Do actual event loop */ 1809 X11_XIfEvent(data->display, &e, X11Toolkit_EventTest, (XPointer)data); 1810 X11Toolkit_ProcessWindowEvents(data, &e); 1811 } 1812} 1813 1814 1815void X11Toolkit_ResizeWindow(SDL_ToolkitWindowX11 *data, int w, int h) { 1816 if (!data->pixmap) { 1817 data->window_width = w; 1818 data->window_height = h; 1819 } else { 1820 data->window_width = SDL_lroundf((w/data->iscale) * data->scale); 1821 data->window_height = SDL_lroundf((h/data->iscale) * data->scale); 1822 data->pixmap_width = w; 1823 data->pixmap_height = h; 1824 X11_XFreePixmap(data->display, data->drawable); 1825 X11Toolkit_InitWindowPixmap(data); 1826 } 1827 1828 X11_XResizeWindow(data->display, data->window, data->window_width, data->window_height); 1829} 1830 1831static void X11Toolkit_DestroyIconControl(SDL_ToolkitControlX11 *control) { 1832 SDL_ToolkitIconControlX11 *icon_control; 1833 1834 icon_control = (SDL_ToolkitIconControlX11 *)control; 1835 X11_XFreeFont(control->window->display, icon_control->icon_char_font); 1836 SDL_free(control); 1837} 1838 1839static void X11Toolkit_DrawIconControl(SDL_ToolkitControlX11 *control) { 1840 SDL_ToolkitIconControlX11 *icon_control; 1841 1842 icon_control = (SDL_ToolkitIconControlX11 *)control; 1843 control->rect.w -= 2 * control->window->iscale; 1844 control->rect.h -= 2 * control->window->iscale; 1845 X11_XSetForeground(control->window->display, control->window->ctx, icon_control->xcolor_bg_shadow.pixel); 1846 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); 1847 1848 switch (icon_control->flags & (SDL_MESSAGEBOX_ERROR | SDL_MESSAGEBOX_WARNING | SDL_MESSAGEBOX_INFORMATION)) { 1849 case SDL_MESSAGEBOX_ERROR: 1850 X11_XSetForeground(control->window->display, control->window->ctx, icon_control->xcolor_red_darker.pixel); 1851 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); 1852 X11_XSetForeground(control->window->display, control->window->ctx, icon_control->xcolor_red.pixel); 1853 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); 1854 X11_XSetForeground(control->window->display, control->window->ctx, icon_control->xcolor_white.pixel); 1855 break; 1856 case SDL_MESSAGEBOX_WARNING: 1857 X11_XSetForeground(control->window->display, control->window->ctx, icon_control->xcolor_black.pixel); 1858 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); 1859 X11_XSetForeground(control->window->display, control->window->ctx, icon_control->xcolor_yellow.pixel); 1860 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); 1861 X11_XSetForeground(control->window->display, control->window->ctx, icon_control->xcolor_black.pixel); 1862 break; 1863 case SDL_MESSAGEBOX_INFORMATION: 1864 X11_XSetForeground(control->window->display, control->window->ctx, icon_control->xcolor_white.pixel); 1865 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); 1866 X11_XSetForeground(control->window->display, control->window->ctx, icon_control->xcolor_blue.pixel); 1867 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); 1868 X11_XSetForeground(control->window->display, control->window->ctx, icon_control->xcolor_white.pixel); 1869 break; 1870 } 1871 X11_XSetFont(control->window->display, control->window->ctx, icon_control->icon_char_font->fid); 1872 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); 1873 if (!control->window->utf8) { 1874 X11_XSetFont(control->window->display, control->window->ctx, control->window->font_struct->fid); 1875 } 1876 1877 control->rect.w += 2 * control->window->iscale; 1878 control->rect.h += 2 * control->window->iscale; 1879} 1880 1881static void X11Toolkit_CalculateIconControl(SDL_ToolkitControlX11 *base_control) { 1882 SDL_ToolkitIconControlX11 *control; 1883 int icon_char_w; 1884 int icon_wh; 1885 1886 control = (SDL_ToolkitIconControlX11 *)base_control; 1887 X11Toolkit_GetTextWidthHeightForFont(control->icon_char_font, &control->icon_char, 1, &icon_char_w, &control->icon_char_h, &control->icon_char_a, NULL); 1888 base_control->rect.w = icon_char_w; 1889 base_control->rect.h = control->icon_char_h; 1890 icon_wh = SDL_max(icon_char_w, control->icon_char_h) + SDL_TOOLKIT_X11_ELEMENT_PADDING * 2 * base_control->window->iscale; 1891 base_control->rect.w = icon_wh; 1892 base_control->rect.h = icon_wh; 1893 base_control->rect.y = 0; 1894 base_control->rect.x = 0; 1895 control->icon_char_y = control->icon_char_a + (base_control->rect.h - control->icon_char_h)/2; 1896 control->icon_char_x = (base_control->rect.w - icon_char_w)/2; 1897 base_control->rect.w += 2 * base_control->window->iscale; 1898 base_control->rect.h += 2 * base_control->window->iscale; 1899} 1900 1901static void X11Toolkit_OnIconControlScaleChange(SDL_ToolkitControlX11 *base_control) { 1902 SDL_ToolkitIconControlX11 *control; 1903 char *font; 1904 1905 control = (SDL_ToolkitIconControlX11 *)base_control; 1906 X11_XFreeFont(base_control->window->display, control->icon_char_font); 1907 SDL_asprintf(&font, g_IconFont, G_ICONFONT_SIZE * base_control->window->iscale); 1908 control->icon_char_font = X11_XLoadQueryFont(base_control->window->display, font); 1909 SDL_free(font); 1910 if (!control->icon_char_font) { 1911 SDL_asprintf(&font, g_ToolkitFontLatin1, G_TOOLKITFONT_SIZE * base_control->window->iscale); 1912 control->icon_char_font = X11_XLoadQueryFont(base_control->window->display, font); 1913 SDL_free(font); 1914 } 1915} 1916 1917SDL_ToolkitControlX11 *X11Toolkit_CreateIconControl(SDL_ToolkitWindowX11 *window, SDL_MessageBoxFlags flags) { 1918 SDL_ToolkitIconControlX11 *control; 1919 SDL_ToolkitControlX11 *base_control; 1920 char *font; 1921 1922 /* Create control struct */ 1923 control = (SDL_ToolkitIconControlX11 *)SDL_malloc(sizeof(SDL_ToolkitIconControlX11)); 1924 base_control = (SDL_ToolkitControlX11 *)control; 1925 if (!control) { 1926 SDL_SetError("Unable to allocate icon control structure"); 1927 return NULL; 1928 } 1929 1930 /* Fill out struct */ 1931 base_control->window = window; 1932 base_control->func_draw = X11Toolkit_DrawIconControl; 1933 base_control->func_free = X11Toolkit_DestroyIconControl; 1934 base_control->func_on_state_change = NULL; 1935 base_control->func_calc_size = X11Toolkit_CalculateIconControl; 1936 base_control->func_on_scale_change = X11Toolkit_OnIconControlScaleChange; 1937 base_control->state = SDL_TOOLKIT_CONTROL_STATE_X11_NORMAL; 1938 base_control->selected = false; 1939 base_control->dynamic = false; 1940 base_control->is_default_enter = false; 1941 base_control->is_default_esc = false; 1942 control->flags = flags; 1943 1944 /* Load font */ 1945 SDL_asprintf(&font, g_IconFont, G_ICONFONT_SIZE * window->iscale); 1946 control->icon_char_font = X11_XLoadQueryFont(window->display, font); 1947 SDL_free(font); 1948 if (!control->icon_char_font) { 1949 SDL_asprintf(&font, g_ToolkitFontLatin1, G_TOOLKITFONT_SIZE * window->iscale); 1950 control->icon_char_font = X11_XLoadQueryFont(window->display, font); 1951 SDL_free(font); 1952 if (!control->icon_char_font) { 1953 SDL_free(control); 1954 return NULL; 1955 } 1956 } 1957 1958 /* Set colors */ 1959 switch (flags & (SDL_MESSAGEBOX_ERROR | SDL_MESSAGEBOX_WARNING | SDL_MESSAGEBOX_INFORMATION)) { 1960 case SDL_MESSAGEBOX_ERROR: 1961 control->icon_char = 'X'; 1962 control->xcolor_white.flags = DoRed|DoGreen|DoBlue; 1963 control->xcolor_white.red = 65535; 1964 control->xcolor_white.green = 65535; 1965 control->xcolor_white.blue = 65535; 1966 control->xcolor_red.flags = DoRed|DoGreen|DoBlue; 1967 control->xcolor_red.red = 65535; 1968 control->xcolor_red.green = 0; 1969 control->xcolor_red.blue = 0; 1970 control->xcolor_red_darker.flags = DoRed|DoGreen|DoBlue; 1971 control->xcolor_red_darker.red = 40535; 1972 control->xcolor_red_darker.green = 0; 1973 control->xcolor_red_darker.blue = 0; 1974 X11_XAllocColor(window->display, window->cmap, &control->xcolor_white); 1975 X11_XAllocColor(window->display, window->cmap, &control->xcolor_red); 1976 X11_XAllocColor(window->display, window->cmap, &control->xcolor_red_darker); 1977 break; 1978 case SDL_MESSAGEBOX_WARNING: 1979 control->icon_char = '!'; 1980 control->xcolor_black.flags = DoRed|DoGreen|DoBlue; 1981 control->xcolor_black.red = 0; 1982 control->xcolor_black.green = 0; 1983 control->xcolor_black.blue = 0; 1984 control->xcolor_yellow.flags = DoRed|DoGreen|DoBlue; 1985 control->xcolor_yellow.red = 65535; 1986 control->xcolor_yellow.green = 65535; 1987 control->xcolor_yellow.blue = 0; 1988 X11_XAllocColor(window->display, window->cmap, &control->xcolor_black); 1989 X11_XAllocColor(window->display, window->cmap, &control->xcolor_yellow); 1990 break; 1991 case SDL_MESSAGEBOX_INFORMATION: 1992 control->icon_char = 'i'; 1993 control->xcolor_white.flags = DoRed|DoGreen|DoBlue; 1994 control->xcolor_white.red = 65535; 1995 control->xcolor_white.green = 65535; 1996 control->xcolor_white.blue = 65535; 1997 control->xcolor_blue.flags = DoRed|DoGreen|DoBlue; 1998 control->xcolor_blue.red = 0; 1999 control->xcolor_blue.green = 0; 2000 control->xcolor_blue.blue = 65535; 2001 X11_XAllocColor(window->display, window->cmap, &control->xcolor_white); 2002 X11_XAllocColor(window->display, window->cmap, &control->xcolor_blue); 2003 break; 2004 default: 2005 X11_XFreeFont(window->display, control->icon_char_font); 2006 SDL_free(control); 2007 return NULL; 2008 } 2009 control->xcolor_bg_shadow.flags = DoRed|DoGreen|DoBlue; 2010 if (window->xcolor[SDL_MESSAGEBOX_COLOR_BACKGROUND].red > 32896) { 2011 control->xcolor_bg_shadow.red = SDL_clamp(window->xcolor[SDL_MESSAGEBOX_COLOR_BACKGROUND].red - 12500, 0, 65535); 2012 } else if (window->xcolor[SDL_MESSAGEBOX_COLOR_BACKGROUND].red == 0) { 2013 control->xcolor_bg_shadow.red = SDL_clamp(window->xcolor[SDL_MESSAGEBOX_COLOR_BACKGROUND].red + 9000, 0, 65535); 2014 } else { 2015 control->xcolor_bg_shadow.red = SDL_clamp(window->xcolor[SDL_MESSAGEBOX_COLOR_BACKGROUND].red - 3000, 0, 65535); 2016 } 2017 2018 if (window->xcolor[SDL_MESSAGEBOX_COLOR_BACKGROUND].green > 32896) { 2019 control->xcolor_bg_shadow.green = SDL_clamp(window->xcolor[SDL_MESSAGEBOX_COLOR_BACKGROUND].green - 12500, 0, 65535); 2020 } else if (window->xcolor[SDL_MESSAGEBOX_COLOR_BACKGROUND].green == 0) { 2021 control->xcolor_bg_shadow.green = SDL_clamp(window->xcolor[SDL_MESSAGEBOX_COLOR_BACKGROUND].green + 9000, 0, 65535); 2022 } else { 2023 control->xcolor_bg_shadow.green = SDL_clamp(window->xcolor[SDL_MESSAGEBOX_COLOR_BACKGROUND].green - 3000, 0, 65535); 2024 } 2025 2026 if (window->xcolor[SDL_MESSAGEBOX_COLOR_BACKGROUND].blue > 32896) { 2027 control->xcolor_bg_shadow.blue = SDL_clamp(window->xcolor[SDL_MESSAGEBOX_COLOR_BACKGROUND].blue - 12500, 0, 65535); 2028 } else if (window->xcolor[SDL_MESSAGEBOX_COLOR_BACKGROUND].blue == 0) { 2029 control->xcolor_bg_shadow.blue = SDL_clamp(window->xcolor[SDL_MESSAGEBOX_COLOR_BACKGROUND].blue + 9000, 0, 65535); 2030 } else { 2031 control->xcolor_bg_shadow.blue = SDL_clamp(window->xcolor[SDL_MESSAGEBOX_COLOR_BACKGROUND].blue - 3000, 0, 65535); 2032 } 2033 X11_XAllocColor(window->display, window->cmap, &control->xcolor_bg_shadow); 2034 2035 /* Sizing and positioning */ 2036 X11Toolkit_CalculateIconControl(base_control); 2037 2038 X11Toolkit_AddControlToWindow(window, base_control); 2039 return base_control; 2040} 2041 2042bool X11Toolkit_NotifyControlOfSizeChange(SDL_ToolkitControlX11 *control) { 2043 if (control->func_calc_size) { 2044 control->func_calc_size(control); 2045 return true; 2046 } else { 2047 return false; 2048 } 2049} 2050 2051static void X11Toolkit_CalculateButtonControl(SDL_ToolkitControlX11 *control) { 2052 SDL_ToolkitButtonControlX11 *button_control; 2053 2054 button_control = (SDL_ToolkitButtonControlX11 *)control; 2055 X11Toolkit_GetTextElementsRect(button_control->text, &button_control->text_rect); 2056 if (control->do_size) { 2057 control->rect.w = SDL_TOOLKIT_X11_ELEMENT_PADDING_3 * 2 * control->window->iscale + button_control->text_rect.w; 2058 control->rect.h = SDL_TOOLKIT_X11_ELEMENT_PADDING_3 * 2 * control->window->iscale + button_control->text_rect.h; 2059 } 2060 button_control->text_rect.x = (control->rect.w - button_control->text_rect.w)/2; 2061 button_control->text_rect.y = (control->rect.h - button_control->text_rect.h)/2; 2062} 2063 2064 2065static void X11Toolkit_DrawButtonControl(SDL_ToolkitControlX11 *control) { 2066 SDL_ToolkitButtonControlX11 *button_control; 2067 2068 button_control = (SDL_ToolkitButtonControlX11 *)control; 2069 2070 X11_XSetForeground(control->window->display, control->window->ctx, control->window->xcolor[SDL_MESSAGEBOX_COLOR_TEXT].pixel); 2071 /* Draw bevel */ 2072 if (control->state == SDL_TOOLKIT_CONTROL_STATE_X11_PRESSED || control->state == SDL_TOOLKIT_CONTROL_STATE_X11_PRESSED_HELD) { 2073 X11_XSetForeground(control->window->display, control->window->ctx, control->window->xcolor_bevel_d.pixel); 2074 X11_XFillRectangle(control->window->display, control->window->drawable, control->window->ctx, 2075 control->rect.x, control->rect.y, 2076 control->rect.w, control->rect.h); 2077 2078 X11_XSetForeground(control->window->display, control->window->ctx, control->window->xcolor_bevel_l2.pixel); 2079 X11_XFillRectangle(control->window->display, control->window->drawable, control->window->ctx, 2080 control->rect.x, control->rect.y, 2081 control->rect.w - (1* control->window->iscale), control->rect.h - (1* control->window->iscale)); 2082 2083 X11_XSetForeground(control->window->display, control->window->ctx, control->window->xcolor_bevel_l1.pixel); 2084 X11_XFillRectangle(control->window->display, control->window->drawable, control->window->ctx, 2085 control->rect.x + 1 * control->window->iscale, control->rect.y + 1 * control->window->iscale, 2086 control->rect.w - 3 * control->window->iscale, control->rect.h - 2 * control->window->iscale); 2087 2088 X11_XSetForeground(control->window->display, control->window->ctx, control->window->xcolor[SDL_MESSAGEBOX_COLOR_BUTTON_BORDER].pixel); 2089 X11_XFillRectangle(control->window->display, control->window->drawable, control->window->ctx, 2090 control->rect.x + 1 * control->window->iscale, control->rect.y + 1 * control->window->iscale, 2091 control->rect.w - 3 * control->window->iscale, control->rect.h - 3 * control->window->iscale); 2092 2093 X11_XSetForeground(control->window->display, control->window->ctx, control->window->xcolor_pressed.pixel); 2094 X11_XFillRectangle(control->window->display, control->window->drawable, control->window->ctx, 2095 control->rect.x + 2 * control->window->iscale, control->rect.y + 2 * control->window->iscale, 2096 control->rect.w - 4 * control->window->iscale, control->rect.h - 4 * control->window->iscale); 2097 } else { 2098 if (control->selected) { 2099 X11_XSetForeground(control->window->display, control->window->ctx, control->window->xcolor_bevel_d.pixel); 2100 X11_XFillRectangle(control->window->display, control->window->drawable, control->window->ctx, 2101 control->rect.x, control->rect.y, 2102 control->rect.w, control->rect.h); 2103 2104 X11_XSetForeground(control->window->display, control->window->ctx, control->window->xcolor_bevel_l2.pixel); 2105 X11_XFillRectangle(control->window->display, control->window->drawable, control->window->ctx, 2106 control->rect.x + 1 * control->window->iscale, control->rect.y + 1 * control->window->iscale, 2107 control->rect.w - 3 * control->window->iscale, control->rect.h - 3 * control->window->iscale); 2108 2109 X11_XSetForeground(control->window->display, control->window->ctx, control->window->xcolor[SDL_MESSAGEBOX_COLOR_BUTTON_BORDER].pixel); 2110 X11_XFillRectangle(control->window->display, control->window->drawable, control->window->ctx, 2111 control->rect.x + 2 * control->window->iscale, control->rect.y + 2 * control->window->iscale, 2112 control->rect.w - 4 * control->window->iscale, control->rect.h - 4 * control->window->iscale); 2113 2114 X11_XSetForeground(control->window->display, control->window->ctx, control->window->xcolor_bevel_l1.pixel); 2115 X11_XFillRectangle(control->window->display, control->window->drawable, control->window->ctx, 2116 control->rect.x + 2 * control->window->iscale, control->rect.y + 2 * control->window->iscale, 2117 control->rect.w - 5 * control->window->iscale, control->rect.h - 5 * control->window->iscale); 2118 2119 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); 2120 X11_XFillRectangle(control->window->display, control->window->drawable, control->window->ctx, 2121 control->rect.x + 3 * control->window->iscale, control->rect.y + 3 * control->window->iscale, 2122 control->rect.w - 6 * control->window->iscale, control->rect.h - 6 * control->window->iscale); 2123 } else { 2124 X11_XSetForeground(control->window->display, control->window->ctx, control->window->xcolor_bevel_d.pixel); 2125 X11_XFillRectangle(control->window->display, control->window->drawable, control->window->ctx, 2126 control->rect.x, control->rect.y, 2127 control->rect.w, control->rect.h); 2128 2129 X11_XSetForeground(control->window->display, control->window->ctx, control->window->xcolor_bevel_l2.pixel); 2130 X11_XFillRectangle(control->window->display, control->window->drawable, control->window->ctx, 2131 control->rect.x, control->rect.y, 2132 control->rect.w - 1 * control->window->iscale, control->rect.h - 1 * control->window->iscale); 2133 2134 X11_XSetForeground(control->window->display, control->window->ctx, control->window->xcolor[SDL_MESSAGEBOX_COLOR_BUTTON_BORDER].pixel); 2135 X11_XFillRectangle(control->window->display, control->window->drawable, control->window->ctx, 2136 control->rect.x + 1 * control->window->iscale, control->rect.y + 1 * control->window->iscale, 2137 control->rect.w - 2 * control->window->iscale, control->rect.h - 2 * control->window->iscale); 2138 2139 X11_XSetForeground(control->window->display, control->window->ctx, control->window->xcolor_bevel_l1.pixel); 2140 X11_XFillRectangle(control->window->display, control->window->drawable, control->window->ctx, 2141 control->rect.x + 1 * control->window->iscale, control->rect.y + 1 * control->window->iscale, 2142 control->rect.w - 3 * control->window->iscale, control->rect.h - 3 * control->window->iscale); 2143 2144 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); 2145 X11_XFillRectangle(control->window->display, control->window->drawable, control->window->ctx, 2146 control->rect.x + 2 * control->window->iscale, control->rect.y + 2 * control->window->iscale, 2147 control->rect.w - 4 * control->window->iscale, control->rect.h - 4 * control->window->iscale); 2148 } 2149 } 2150 2151 X11_XSetForeground(control->window->display, control->window->ctx, control->window->xcolor[SDL_MESSAGEBOX_COLOR_TEXT].pixel); 2152 X11Toolkit_DrawTextElements(control->window, button_control->text, control->rect.x + button_control->text_rect.x, control->rect.y + button_control->text_rect.y); 2153} 2154 2155static void X11Toolkit_OnButtonControlStateChange(SDL_ToolkitControlX11 *control) { 2156 SDL_ToolkitButtonControlX11 *button_control; 2157 2158 button_control = (SDL_ToolkitButtonControlX11 *)control; 2159 if (button_control->cb && control->state == SDL_TOOLKIT_CONTROL_STATE_X11_PRESSED) { 2160 button_control->cb(control, button_control->cb_data); 2161 } 2162} 2163 2164static void X11Toolkit_DestroyButtonControl(SDL_ToolkitControlX11 *control) { 2165 SDL_ToolkitButtonControlX11 *button_control; 2166 2167 button_control = (SDL_ToolkitButtonControlX11 *)control; 2168 2169 X11Toolkit_FreeTextElements(button_control->text); 2170 2171 SDL_free(control); 2172} 2173 2174SDL_ToolkitControlX11 *X11Toolkit_CreateButtonControl(SDL_ToolkitWindowX11 *window, const SDL_MessageBoxButtonData *data) { 2175 SDL_ToolkitButtonControlX11 *control; 2176 SDL_ToolkitControlX11 *base_control; 2177 2178 control = (SDL_ToolkitButtonControlX11 *)SDL_malloc(sizeof(SDL_ToolkitButtonControlX11)); 2179 base_control = (SDL_ToolkitControlX11 *)control; 2180 if (!control) { 2181 SDL_SetError("Unable to allocate button control structure"); 2182 return NULL; 2183 } 2184 base_control->window = window; 2185 base_control->state = SDL_TOOLKIT_CONTROL_STATE_X11_NORMAL; 2186 base_control->func_calc_size = X11Toolkit_CalculateButtonControl; 2187 base_control->func_draw = X11Toolkit_DrawButtonControl; 2188 base_control->func_on_state_change = X11Toolkit_OnButtonControlStateChange; 2189 base_control->func_free = X11Toolkit_DestroyButtonControl; 2190 base_control->func_on_scale_change = NULL; 2191 base_control->state = SDL_TOOLKIT_CONTROL_STATE_X11_NORMAL; 2192 base_control->selected = false; 2193 base_control->dynamic = true; 2194 base_control->is_default_enter = false; 2195 base_control->is_default_esc = false; 2196 if (data->flags & SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT) { 2197 base_control->is_default_esc = true; 2198 } 2199 if (data->flags & SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT) { 2200 base_control->is_default_enter = true; 2201 base_control->selected = true; 2202 } 2203 control->cb = NULL; 2204 control->data = data; 2205#ifdef HAVE_FRIBIDI_H 2206 control->text = X11Toolkit_MakeTextElements(base_control->window, (char *)control->data->text, SDL_strlen(control->data->text), NULL); 2207#else 2208 control->text = X11Toolkit_MakeTextElements(base_control->window, (char *)control->data->text, SDL_strlen(control->data->text)); 2209#endif 2210 X11Toolkit_ShapeTextElements(base_control->window, control->text); 2211 2212 base_control->do_size = true; 2213 X11Toolkit_CalculateButtonControl(base_control); 2214 base_control->do_size = false; 2215 2216 X11Toolkit_AddControlToWindow(window, base_control); 2217 return base_control; 2218} 2219 2220void X11Toolkit_RegisterCallbackForButtonControl(SDL_ToolkitControlX11 *control, void *data, void (*cb)(struct SDL_ToolkitControlX11 *, void *)) { 2221 SDL_ToolkitButtonControlX11 *button_control; 2222 2223 button_control = (SDL_ToolkitButtonControlX11 *)control; 2224 button_control->cb_data = data; 2225 button_control->cb = cb; 2226} 2227 2228const SDL_MessageBoxButtonData *X11Toolkit_GetButtonControlData(SDL_ToolkitControlX11 *control) { 2229 SDL_ToolkitButtonControlX11 *button_control; 2230 2231 button_control = (SDL_ToolkitButtonControlX11 *)control; 2232 return button_control->data; 2233} 2234 2235void X11Toolkit_DestroyWindow(SDL_ToolkitWindowX11 *data) { 2236 int i; 2237 2238 if (!data) { 2239 return; 2240 } 2241 2242#if SDL_GRAB 2243 if (data->mode == SDL_TOOLKIT_WINDOW_MODE_X11_MENU || data->mode== SDL_TOOLKIT_WINDOW_MODE_X11_TOOLTIP) { 2244 X11_XUngrabPointer(data->display, CurrentTime); 2245 X11_XUngrabKeyboard(data->display, CurrentTime); 2246 } 2247#endif 2248 2249 for (i = 0; i < data->controls_sz; i++) { 2250 if (data->controls[i]->func_free) { 2251 data->controls[i]->func_free(data->controls[i]); 2252 } 2253 } 2254 SDL_free(data->controls); 2255 SDL_free(data->dyn_controls); 2256 2257 if (data->popup_windows) { 2258 SDL_ListClear(&data->popup_windows); 2259 } 2260 2261 if (data->pixmap) { 2262 X11_XFreePixmap(data->display, data->drawable); 2263 } 2264 2265#ifndef NO_SHARED_MEMORY 2266 if (data->pixmap && data->shm) { 2267 X11_XShmDetach(data->display, &data->shm_info); 2268 if (!data->shm_pixmap) { 2269 XDestroyImage(data->image); 2270 } 2271 shmdt(data->shm_info.shmaddr); 2272 } 2273#endif 2274 2275#ifdef X_HAVE_UTF8_STRING 2276 if (data->font_set) { 2277 X11_XFreeFontSet(data->display, data->font_set); 2278 data->font_set = NULL; 2279 } 2280#endif 2281 2282 if (data->font_struct) { 2283 X11_XFreeFont(data->display, data->font_struct); 2284 data->font_struct = NULL; 2285 } 2286 2287#ifdef SDL_VIDEO_DRIVER_X11_XDBE 2288 if (SDL_X11_HAVE_XDBE && data->xdbe && !data->pixmap) { 2289 X11_XdbeDeallocateBackBufferName(data->display, data->buf); 2290 } 2291#endif 2292 2293 if (data->xsettings) { 2294 xsettings_client_destroy(data->xsettings); 2295 } 2296 2297 X11_XFreeGC(data->display, data->ctx); 2298 2299 if (data->display) { 2300 if (data->window != None) { 2301 X11_XWithdrawWindow(data->display, data->window, data->screen); 2302 X11_XDestroyWindow(data->display, data->window); 2303 data->window = None; 2304 } 2305 2306 if (data->display_close) { 2307 X11_XCloseDisplay(data->display); 2308 } 2309 data->display = NULL; 2310 } 2311 2312#if SDL_SET_LOCALE 2313 if (data->origlocale && (data->mode == SDL_TOOLKIT_WINDOW_MODE_X11_DIALOG)) { 2314 (void)setlocale(LC_ALL, data->origlocale); 2315 SDL_free(data->origlocale); 2316 } 2317#endif 2318 2319#ifdef HAVE_FRIBIDI_H 2320 SDL_FriBidi_Destroy(data->fribidi); 2321#endif 2322 2323#ifdef HAVE_LIBTHAI_H 2324 SDL_LibThai_Destroy(data->th); 2325#endif 2326 2327 SDL_free(data); 2328} 2329 2330static int X11Toolkit_CountLinesOfText(const char *text) 2331{ 2332 int result = 0; 2333 while (text && *text) { 2334 const char *lf = SDL_strchr(text, '\n'); 2335 result++; // even without an endline, this counts as a line. 2336 text = lf ? lf + 1 : NULL; 2337 } 2338 return result; 2339} 2340 2341static void X11Toolkit_DrawLabelControl(SDL_ToolkitControlX11 *control) { 2342 SDL_ToolkitLabelControlX11 *label_control; 2343 int i; 2344 2345 label_control = (SDL_ToolkitLabelControlX11 *)control; 2346 X11_XSetForeground(control->window->display, control->window->ctx, control->window->xcolor[SDL_MESSAGEBOX_COLOR_TEXT].pixel); 2347 for (i = 0; i < label_control->sz; i++) { 2348 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); 2349 } 2350} 2351 2352static void X11Toolkit_DestroyLabelControl(SDL_ToolkitControlX11 *control) { 2353 SDL_ToolkitLabelControlX11 *label_control; 2354 int i; 2355 2356 label_control = (SDL_ToolkitLabelControlX11 *)control; 2357 for (i = 0; i < label_control->sz; i++) { 2358 X11Toolkit_FreeTextElements(label_control->lines[i].text); 2359 } 2360 SDL_free(label_control->lines); 2361 SDL_free(label_control); 2362} 2363 2364static void X11Toolkit_CalculateLabelControl(SDL_ToolkitControlX11 *base_control) { 2365 SDL_ToolkitLabelControlX11 *control; 2366 int i; 2367 2368 control = (SDL_ToolkitLabelControlX11 *)base_control; 2369 2370 if (base_control->do_size) { 2371 base_control->rect.w = 0; 2372 base_control->rect.h = 0; 2373 } 2374 2375 for (i = 0; i < control->sz; i++) { 2376 int font_h; 2377 2378 font_h = X11Toolkit_GetTextElementsRect(control->lines[i].text, &control->lines[i].rect); 2379 2380 if (base_control->do_size) { 2381 base_control->rect.w = SDL_max(base_control->rect.w, control->lines[i].rect.w); 2382 } 2383 2384 if (i > 0) { 2385 control->lines[i].rect.y = font_h + control->lines[i - 1].rect.y; 2386 } else { 2387 control->lines[i].rect.y = 0; 2388 } 2389 } 2390 2391#ifdef HAVE_FRIBIDI_H 2392 if (base_control->window->fribidi) { 2393 FriBidiParType first_ndn_dir; 2394 int last_ndn; 2395 2396 first_ndn_dir = FRIBIDI_PAR_LTR; 2397 for (i = 0; i < control->sz; i++) { 2398 if (control->lines[i].par != FRIBIDI_PAR_ON) { 2399 first_ndn_dir = control->lines[i].par; 2400 } 2401 } 2402 2403 last_ndn = -1; 2404 for (i = 0; i < control->sz; i++) { 2405 switch (control->lines[i].par) { 2406 case FRIBIDI_PAR_LTR: 2407 control->lines[i].rect.x = 0; 2408 last_ndn = i; 2409 break; 2410 case FRIBIDI_PAR_RTL: 2411 control->lines[i].rect.x = base_control->rect.w - control->lines[i].rect.w; 2412 last_ndn = i; 2413 break; 2414 default: 2415 if (last_ndn != -1) { 2416 if (control->lines[last_ndn].par == FRIBIDI_PAR_RTL) { 2417 control->lines[i].rect.x = base_control->rect.w - control->lines[i].rect.w; 2418 } else { 2419 control->lines[i].rect.x = 0; 2420 } 2421 } else { 2422 if (first_ndn_dir == FRIBIDI_PAR_RTL) { 2423 control->lines[i].rect.x = base_control->rect.w - control->lines[i].rect.w; 2424 } else { 2425 control->lines[i].rect.x = 0; 2426 } 2427 } 2428 } 2429 } 2430 } 2431#endif 2432 2433 if (base_control->do_size && control->sz) { 2434 base_control->rect.h = control->lines[control->sz - 1].rect.y + control->lines[control->sz - 1].rect.h; 2435 } 2436} 2437 2438SDL_ToolkitControlX11 *X11Toolkit_CreateLabelControl(SDL_ToolkitWindowX11 *window, char *utf8) { 2439 SDL_ToolkitLabelControlX11 *control; 2440 SDL_ToolkitControlX11 *base_control; 2441 int i; 2442 2443 if (!utf8) { 2444 return NULL; 2445 } 2446 2447 if (!SDL_strcmp(utf8, "")) { 2448 return NULL; 2449 } 2450 control = (SDL_ToolkitLabelControlX11 *)SDL_malloc(sizeof(SDL_ToolkitLabelControlX11)); 2451 base_control = (SDL_ToolkitControlX11 *)control; 2452 if (!control) { 2453 SDL_SetError("Unable to allocate label control structure"); 2454 return NULL; 2455 } 2456 base_control->window = window; 2457 base_control->func_draw = X11Toolkit_DrawLabelControl; 2458 base_control->func_on_state_change = NULL; 2459 base_control->func_calc_size = X11Toolkit_CalculateLabelControl; 2460 base_control->func_free = X11Toolkit_DestroyLabelControl; 2461 base_control->func_on_scale_change = NULL; 2462 base_control->state = SDL_TOOLKIT_CONTROL_STATE_X11_NORMAL; 2463 base_control->selected = false; 2464 base_control->dynamic = false; 2465 base_control->rect.w = 0; 2466 base_control->rect.h = 0; 2467 base_control->is_default_enter = false; 2468 base_control->is_default_esc = false; 2469 2470 control->sz = X11Toolkit_CountLinesOfText(utf8); 2471 control->lines = SDL_calloc(control->sz, sizeof(SDL_ToolkitLabelControlLineX11)); 2472 for (i = 0; i < control->sz; i++) { 2473 const char *lf = SDL_strchr(utf8, '\n'); 2474 const int length = lf ? (lf - utf8) : SDL_strlen(utf8); 2475 int sz; 2476 2477 sz = length; 2478 if (lf && (lf > utf8) && (lf[-1] == '\r')) { 2479 sz--; 2480 } 2481 2482#ifdef HAVE_FRIBIDI_H 2483 control->lines[i].text = X11Toolkit_MakeTextElements(base_control->window, (char *)utf8, sz, &control->lines[i].par); 2484#else 2485 control->lines[i].text = X11Toolkit_MakeTextElements(base_control->window, (char *)utf8, sz); 2486#endif 2487 X11Toolkit_ShapeTextElements(base_control->window, control->lines[i].text); 2488 2489 utf8 += length + 1; 2490 if (!lf) { 2491 break; 2492 } 2493 } 2494 2495 base_control->do_size = true; 2496 X11Toolkit_CalculateLabelControl(base_control); 2497 base_control->do_size = false; 2498 X11Toolkit_AddControlToWindow(window, base_control); 2499 2500 return base_control; 2501} 2502 2503int X11Toolkit_GetLabelControlFirstLineHeight(SDL_ToolkitControlX11 *control) { 2504 SDL_ToolkitLabelControlX11 *label_control; 2505 2506 label_control = (SDL_ToolkitLabelControlX11 *)control; 2507 2508 return label_control->lines[0].rect.h; 2509} 2510 2511void X11Toolkit_SignalWindowClose(SDL_ToolkitWindowX11 *data) { 2512 data->close = true; 2513} 2514 2515#endif // SDL_VIDEO_DRIVER_X11 2516
[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.