Blender V4.5
wm_window.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved. 2007 Blender Authors.
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
10
11#include <algorithm>
12#include <chrono>
13#include <cmath>
14#include <cstdio>
15#include <cstdlib>
16#include <cstring>
17#include <thread>
18
19#include <fmt/format.h>
20
21#include "CLG_log.h"
22
23#include "DNA_listBase.h"
24#include "DNA_screen_types.h"
26#include "DNA_workspace_types.h"
27
28#include "MEM_guardedalloc.h"
29
30#include "GHOST_C-api.h"
31
32#include "BLI_listbase.h"
33#include "BLI_math_vector.h"
34#include "BLI_path_utils.hh"
35#include "BLI_rect.h"
36#include "BLI_string.h"
37#include "BLI_string_utf8.h"
38#include "BLI_system.h"
39#include "BLI_time.h"
40#include "BLI_utildefines.h"
41
42#include "BLT_translation.hh"
43
44#include "BKE_blender_version.h"
45#include "BKE_context.hh"
46#include "BKE_global.hh"
47#include "BKE_icons.h"
48#include "BKE_layer.hh"
49#include "BKE_main.hh"
50#include "BKE_report.hh"
51#include "BKE_screen.hh"
52#include "BKE_wm_runtime.hh"
53#include "BKE_workspace.hh"
54
55#include "RNA_access.hh"
56#include "RNA_enum_types.hh"
57
58#include "WM_api.hh"
59#include "WM_keymap.hh"
60#include "WM_types.hh"
61#include "wm.hh"
62#include "wm_draw.hh"
63#include "wm_event_system.hh"
64#include "wm_files.hh"
65#include "wm_window.hh"
66#include "wm_window_private.hh"
67#ifdef WITH_XR_OPENXR
68# include "wm_xr.hh"
69#endif
70
71#include "ED_anim_api.hh"
72#include "ED_fileselect.hh"
73#include "ED_render.hh"
74#include "ED_scene.hh"
75#include "ED_screen.hh"
76
77#include "IMB_imbuf.hh"
78#include "IMB_imbuf_types.hh"
79
80#include "UI_interface.hh"
81#include "UI_interface_icons.hh"
82
83#include "BLF_api.hh"
84#include "GPU_context.hh"
85#include "GPU_framebuffer.hh"
86#include "GPU_init_exit.hh"
87
88#include "UI_resources.hh"
89
90/* For assert. */
91#ifndef NDEBUG
92# include "BLI_threads.h"
93#endif
94
95/* The global to talk to GHOST. */
96static GHOST_SystemHandle g_system = nullptr;
97#if !(defined(WIN32) || defined(__APPLE__))
98static const char *g_system_backend_id = nullptr;
99#endif
100
106
107#define GHOST_WINDOW_STATE_DEFAULT GHOST_kWindowStateMaximized
108
133
134/* -------------------------------------------------------------------- */
137
138static const struct {
139 uint8_t flag;
142} g_modifier_table[] = {
143 {KM_SHIFT,
146 {KM_CTRL,
149 {KM_ALT,
152 {KM_OSKEY,
155 {KM_HYPER,
159
164
166
167/* -------------------------------------------------------------------- */
170
171static void wm_window_set_drawable(wmWindowManager *wm, wmWindow *win, bool activate);
172static bool wm_window_timers_process(const bContext *C, int *sleep_us_p);
173static uint8_t wm_ghost_modifier_query(const enum ModSide side);
174
175bool wm_get_screensize(int r_size[2])
176{
177 uint32_t uiwidth, uiheight;
178 if (GHOST_GetMainDisplayDimensions(g_system, &uiwidth, &uiheight) == GHOST_kFailure) {
179 return false;
180 }
181 r_size[0] = uiwidth;
182 r_size[1] = uiheight;
183 return true;
184}
185
186bool wm_get_desktopsize(int r_size[2])
187{
188 uint32_t uiwidth, uiheight;
189 if (GHOST_GetAllDisplayDimensions(g_system, &uiwidth, &uiheight) == GHOST_kFailure) {
190 return false;
191 }
192 r_size[0] = uiwidth;
193 r_size[1] = uiheight;
194 return true;
195}
196
198static void wm_window_check_size(rcti *rect)
199{
200 blender::int2 scr_size;
201 if (wm_get_screensize(scr_size)) {
202 if (BLI_rcti_size_x(rect) > scr_size[0]) {
203 BLI_rcti_resize_x(rect, scr_size[0]);
204 }
205 if (BLI_rcti_size_y(rect) > scr_size[1]) {
206 BLI_rcti_resize_y(rect, scr_size[1]);
207 }
208 }
209}
210
212{
213 if (UNLIKELY(!win->ghostwin)) {
214 return;
215 }
216
217 /* Prevents non-drawable state of main windows (bugs #22967,
218 * #25071 and possibly #22477 too). Always clear it even if
219 * this window was not the drawable one, because we mess with
220 * drawing context to discard the GW context. */
222
223 if (win == wm->winactive) {
224 wm->winactive = nullptr;
225 }
226
227 /* We need this window's GPU context active to discard it. */
228 GHOST_ActivateWindowDrawingContext(static_cast<GHOST_WindowHandle>(win->ghostwin));
229 GPU_context_active_set(static_cast<GPUContext *>(win->gpuctx));
230
231 /* Delete local GPU context. */
232 GPU_context_discard(static_cast<GPUContext *>(win->gpuctx));
233
234 GHOST_DisposeWindow(g_system, static_cast<GHOST_WindowHandle>(win->ghostwin));
235 win->ghostwin = nullptr;
236 win->gpuctx = nullptr;
237}
238
240{
241 /* Update context. */
242 if (C) {
245
246 if (CTX_wm_window(C) == win) {
247 CTX_wm_window_set(C, nullptr);
248 }
249 }
250
252
253 /* End running jobs, a job end also removes its timer. */
255 if (wt->flags & WM_TIMER_TAGGED_FOR_REMOVAL) {
256 continue;
257 }
258 if (wt->win == win && wt->event_type == TIMERJOBS) {
259 wm_jobs_timer_end(wm, wt);
260 }
261 }
262
263 /* Timer removing, need to call this API function. */
265 if (wt->flags & WM_TIMER_TAGGED_FOR_REMOVAL) {
266 continue;
267 }
268 if (wt->win == win) {
269 WM_event_timer_remove(wm, win, wt);
270 }
271 }
273
274 if (win->eventstate) {
275 MEM_freeN(win->eventstate);
276 }
277 if (win->event_last_handled) {
279 }
282 }
283
284 if (win->cursor_keymap_status) {
286 }
287
289
291
292 wm_ghostwindow_destroy(wm, win);
293
296
297 MEM_delete(win->runtime);
298 MEM_freeN(win);
299}
300
302{
303 int id = 1;
304
305 LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
306 if (id <= win->winid) {
307 id = win->winid + 1;
308 }
309 }
310 return id;
311}
312
313wmWindow *wm_window_new(const Main *bmain, wmWindowManager *wm, wmWindow *parent, bool dialog)
314{
315 wmWindow *win = MEM_callocN<wmWindow>("window");
316
317 BLI_addtail(&wm->windows, win);
318 win->winid = find_free_winid(wm);
319
320 /* Dialogs may have a child window as parent. Otherwise, a child must not be a parent too. */
321 win->parent = (!dialog && parent && parent->parent) ? parent->parent : parent;
322 win->stereo3d_format = MEM_callocN<Stereo3dFormat>("Stereo 3D Format (window)");
324 win->runtime = MEM_new<blender::bke::WindowRuntime>(__func__);
325
326 return win;
327}
328
330 wmWindowManager *wm,
331 wmWindow *win_src,
332 const bool duplicate_layout,
333 const bool child)
334{
335 const bool is_dialog = GHOST_IsDialogWindow(static_cast<GHOST_WindowHandle>(win_src->ghostwin));
336 wmWindow *win_parent = (child) ? win_src : win_src->parent;
337 wmWindow *win_dst = wm_window_new(bmain, wm, win_parent, is_dialog);
338 WorkSpace *workspace = WM_window_get_active_workspace(win_src);
339 WorkSpaceLayout *layout_old = WM_window_get_active_layout(win_src);
340
341 win_dst->posx = win_src->posx + 10;
342 win_dst->posy = win_src->posy;
343 win_dst->sizex = win_src->sizex;
344 win_dst->sizey = win_src->sizey;
345
346 win_dst->scene = win_src->scene;
347 STRNCPY(win_dst->view_layer_name, win_src->view_layer_name);
348 BKE_workspace_active_set(win_dst->workspace_hook, workspace);
349 WorkSpaceLayout *layout_new = duplicate_layout ? ED_workspace_layout_duplicate(
350 bmain, workspace, layout_old, win_dst) :
351 layout_old;
352 BKE_workspace_active_layout_set(win_dst->workspace_hook, win_dst->winid, workspace, layout_new);
353
354 *win_dst->stereo3d_format = *win_src->stereo3d_format;
355
356 return win_dst;
357}
358
360 wmWindow *win_src,
361 const bool duplicate_layout,
362 const bool child)
363{
364 Main *bmain = CTX_data_main(C);
366
367 wmWindow *win_dst = wm_window_copy(bmain, wm, win_src, duplicate_layout, child);
368
369 WM_check(C);
370
371 if (win_dst->ghostwin) {
373 return win_dst;
374 }
375 wm_window_close(C, wm, win_dst);
376 return nullptr;
377}
378
380
381/* -------------------------------------------------------------------- */
384
385static void wm_save_file_on_quit_dialog_callback(bContext *C, void * /*user_data*/)
386{
388}
389
400
402{
403 wmWindow *win_ctx = CTX_wm_window(C);
404
405 /* The popup will be displayed in the context window which may not be set
406 * here (this function gets called outside of normal event handling loop). */
407 CTX_wm_window_set(C, win);
408
409 if (U.uiflag & USER_SAVE_PROMPT) {
411 !G.background)
412 {
413 wm_window_raise(win);
415 }
416 else {
418 }
419 }
420 else {
422 }
423
424 CTX_wm_window_set(C, win_ctx);
425}
426
428
429/* -------------------------------------------------------------------- */
432
434{
435 wmWindow *win_other;
436
437 /* First check if there is another main window remaining. */
438 for (win_other = static_cast<wmWindow *>(wm->windows.first); win_other;
439 win_other = win_other->next)
440 {
441 if (win_other != win && win_other->parent == nullptr && !WM_window_is_temp_screen(win_other)) {
442 break;
443 }
444 }
445
446 if (win->parent == nullptr && win_other == nullptr) {
448 return;
449 }
450
451 /* Close child windows. */
452 LISTBASE_FOREACH_MUTABLE (wmWindow *, iter_win, &wm->windows) {
453 if (iter_win->parent == win) {
454 wm_window_close(C, wm, iter_win);
455 }
456 }
457
461
462 BLI_remlink(&wm->windows, win);
463
464 CTX_wm_window_set(C, win); /* Needed by handlers. */
466
468
469 /* For regular use this will _never_ be nullptr,
470 * however we may be freeing an improperly initialized window. */
471 if (screen) {
472 ED_screen_exit(C, win, screen);
473 }
474
475 wm_window_free(C, wm, win);
476
477 /* If temp screen, delete it after window free (it stops jobs that can access it). */
478 if (screen && screen->temp) {
479 Main *bmain = CTX_data_main(C);
480
482 BKE_workspace_layout_remove(bmain, workspace, layout);
484 }
485
487}
488
489void WM_window_title(wmWindowManager *wm, wmWindow *win, const char *title)
490{
491 if (win->ghostwin == nullptr) {
492 return;
493 }
494
495 GHOST_WindowHandle handle = static_cast<GHOST_WindowHandle>(win->ghostwin);
496
497 if (title) {
498 GHOST_SetTitle(handle, title);
499 return;
500 }
501
502 if (win->parent || WM_window_is_temp_screen(win)) {
503 /* Not a main window. */
505 const bool is_single = screen && BLI_listbase_is_single(&screen->areabase);
506 ScrArea *area = (screen) ? static_cast<ScrArea *>(screen->areabase.first) : nullptr;
507 const char *name = "Blender";
508 if (is_single && area && area->spacetype != SPACE_EMPTY) {
509 name = IFACE_(ED_area_name(area).c_str());
510 }
511 GHOST_SetTitle(handle, name);
512 return;
513 }
514
515 /* This path may contain invalid UTF8 byte sequences on UNIX systems,
516 * use `filepath` for display which is sanitized as needed. */
517 const char *filepath_as_bytes = BKE_main_blendfile_path_from_global();
518
519 char _filepath_utf8_buf[FILE_MAX];
520 /* Allow non-UTF8 characters on systems that support it.
521 *
522 * On Wayland, invalid UTF8 characters will disconnect
523 * from the server - exiting immediately. */
524 const char *filepath = (OS_MAC || OS_WINDOWS) ?
525 filepath_as_bytes :
527 strlen(filepath_as_bytes),
528 '?',
529 _filepath_utf8_buf,
530 sizeof(_filepath_utf8_buf));
531
532 const char *filename = BLI_path_basename(filepath);
533 const bool has_filepath = filepath[0] != '\0';
534 const bool native_filepath_display = GHOST_SetPath(handle, filepath_as_bytes) == GHOST_kSuccess;
535 const bool include_filepath = has_filepath && (filepath != filename) && !native_filepath_display;
536
537 /* File saved state. */
538 std::string win_title = wm->file_saved ? "" : "* ";
539
540 /* File name. Show the file extension if the full file path is not included in the title. */
541 if (include_filepath) {
542 const size_t filename_no_ext_len = BLI_path_extension_or_end(filename) - filename;
543 win_title.append(filename, filename_no_ext_len);
544 }
545 else if (has_filepath) {
546 win_title.append(filename);
547 }
548 /* New / Unsaved file default title. Shows "Untitled" on macOS following the Apple HIGs. */
549 else {
550#ifdef __APPLE__
551 win_title.append(IFACE_("Untitled"));
552#else
553 win_title.append(IFACE_("(Unsaved)"));
554#endif
555 }
556
557 if (G_MAIN->recovered) {
558 win_title.append(IFACE_(" (Recovered)"));
559 }
560
561 if (include_filepath) {
562 win_title.append(fmt::format(" [{}]", filepath));
563 }
564
565 win_title.append(fmt::format(" - Blender {}", BKE_blender_version_string()));
566
567 GHOST_SetTitle(handle, win_title.c_str());
568
569 /* Informs GHOST of unsaved changes to set the window modified visual indicator (macOS)
570 * and to give a hint of unsaved changes for a user warning mechanism in case of OS application
571 * terminate request (e.g., OS Shortcut Alt+F4, Command+Q, (...) or session end). */
573}
574
576{
577 float auto_dpi = GHOST_GetDPIHint(static_cast<GHOST_WindowHandle>(win->ghostwin));
578
579 /* Clamp auto DPI to 96, since our font/interface drawing does not work well
580 * with lower sizes. The main case we are interested in supporting is higher
581 * DPI. If a smaller UI is desired it is still possible to adjust UI scale. */
582 auto_dpi = max_ff(auto_dpi, 96.0f);
583
584 /* Lazily init UI scale size, preserving backwards compatibility by
585 * computing UI scale from ratio of previous DPI and auto DPI. */
586 if (U.ui_scale == 0) {
587 int virtual_pixel = (U.virtual_pixel == VIRTUAL_PIXEL_NATIVE) ? 1 : 2;
588
589 if (U.dpi == 0) {
590 U.ui_scale = virtual_pixel;
591 }
592 else {
593 U.ui_scale = (virtual_pixel * U.dpi * 96.0f) / (auto_dpi * 72.0f);
594 }
595
596 CLAMP(U.ui_scale, 0.25f, 4.0f);
597 }
598
599 /* Blender's UI drawing assumes DPI 72 as a good default following macOS
600 * while Windows and Linux use DPI 96. GHOST assumes a default 96 so we
601 * remap the DPI to Blender's convention. */
602 auto_dpi *= GHOST_GetNativePixelSize(static_cast<GHOST_WindowHandle>(win->ghostwin));
603 U.dpi = auto_dpi * U.ui_scale * (72.0 / 96.0f);
604
605 /* Automatically set larger pixel size for high DPI. */
606 int pixelsize = max_ii(1, (U.dpi / 64));
607 /* User adjustment for pixel size. */
608 pixelsize = max_ii(1, pixelsize + U.ui_line_width);
609
610 /* Set user preferences globals for drawing, and for forward compatibility. */
611 U.pixelsize = pixelsize;
612 U.virtual_pixel = (pixelsize == 1) ? VIRTUAL_PIXEL_NATIVE : VIRTUAL_PIXEL_DOUBLE;
613 U.scale_factor = U.dpi / 72.0f;
614 U.inv_scale_factor = 1.0f / U.scale_factor;
615
616 /* Widget unit is 20 pixels at 1X scale. This consists of 18 user-scaled units plus
617 * left and right borders of line-width (pixel-size). */
618 U.widget_unit = int(roundf(18.0f * U.scale_factor)) + (2 * pixelsize);
619}
620
622
623/* -------------------------------------------------------------------- */
626
628{
630 static_cast<GHOST_WindowHandle>(win->ghostwin));
631
633
634 if (ghost_style_flags & GHOST_kDecorationColoredTitleBar) {
636 }
637
638 return wm_style_flags;
639}
640
643{
645 uint ghost_style_flags = GHOST_kDecorationNone;
646
648 ghost_style_flags |= GHOST_kDecorationColoredTitleBar;
649 }
650
652 static_cast<GHOST_WindowHandle>(win->ghostwin),
653 static_cast<GHOST_TWindowDecorationStyleFlags>(ghost_style_flags));
654}
655
656static void wm_window_decoration_style_set_from_theme(const wmWindow *win, const bScreen *screen)
657{
658 /* Set the decoration style settings from the current theme colors.
659 * NOTE: screen may be null. In which case, only the window is used as a theme provider. */
660 GHOST_WindowDecorationStyleSettings decoration_settings = {};
661
662 /* Colored TitleBar Decoration. */
663 /* For main windows, use the top-bar color. */
666 }
667 /* For single editor floating windows, use the editor header color. */
668 else if (screen && BLI_listbase_is_single(&screen->areabase)) {
669 const ScrArea *main_area = static_cast<ScrArea *>(screen->areabase.first);
671 }
672 /* For floating window with multiple editors/areas, use the default space color. */
673 else {
675 }
676
677 float titlebar_bg_color[3], titlebar_fg_color[3];
678 UI_GetThemeColor3fv(TH_BACK, titlebar_bg_color);
679 UI_GetThemeColor3fv(TH_BUTBACK_TEXT, titlebar_fg_color);
680 copy_v3_v3(decoration_settings.colored_titlebar_bg_color, titlebar_bg_color);
681 copy_v3_v3(decoration_settings.colored_titlebar_fg_color, titlebar_fg_color);
682
683 GHOST_SetWindowDecorationStyleSettings(static_cast<GHOST_WindowHandle>(win->ghostwin),
684 decoration_settings);
685}
686
693
705 wmWindow *win,
706 const uint64_t event_time_ms)
707{
708 const uint8_t keymodifier_sided[2] = {
711 };
712 const uint8_t keymodifier = keymodifier_sided[0] | keymodifier_sided[1];
713 const uint8_t keymodifier_eventstate = win->eventstate->modifier;
714 if (keymodifier != keymodifier_eventstate) {
715 GHOST_TEventKeyData kdata{};
716 kdata.key = GHOST_kKeyUnknown;
717 kdata.utf8_buf[0] = '\0';
718 kdata.is_repeat = false;
719 for (int i = 0; i < ARRAY_SIZE(g_modifier_table); i++) {
720 if (keymodifier_eventstate & g_modifier_table[i].flag) {
721 if ((keymodifier & g_modifier_table[i].flag) == 0) {
722 for (int side = 0; side < 2; side++) {
723 if ((keymodifier_sided[side] & g_modifier_table[i].flag) == 0) {
724 kdata.key = g_modifier_table[i].ghost_key_pair[side];
725 wm_event_add_ghostevent(wm, win, GHOST_kEventKeyUp, &kdata, event_time_ms);
726 /* Only ever send one release event
727 * (currently releasing multiple isn't needed and only confuses logic). */
728 break;
729 }
730 }
731 }
732 }
733 else {
734 if (keymodifier & g_modifier_table[i].flag) {
735 for (int side = 0; side < 2; side++) {
736 if (keymodifier_sided[side] & g_modifier_table[i].flag) {
737 kdata.key = g_modifier_table[i].ghost_key_pair[side];
738 wm_event_add_ghostevent(wm, win, GHOST_kEventKeyDown, &kdata, event_time_ms);
739 }
740 }
741 }
742 }
743 }
744 }
745}
746
760 wmWindow *win,
761 const uint64_t event_time_ms)
762{
763 /* Release all held modifiers before de-activating the window. */
764 if (win->eventstate->modifier != 0) {
765 const uint8_t keymodifier_eventstate = win->eventstate->modifier;
766 const uint8_t keymodifier_l = wm_ghost_modifier_query(MOD_SIDE_LEFT);
767 const uint8_t keymodifier_r = wm_ghost_modifier_query(MOD_SIDE_RIGHT);
768 /* NOTE(@ideasman42): when non-zero, there are modifiers held in
769 * `win->eventstate` which are not considered held by the GHOST internal state.
770 * While this should not happen, it's important all modifier held in event-state
771 * receive release events. Without this, so any events generated while the window
772 * is *not* active will have modifiers held. */
773 const uint8_t keymodifier_unhandled = keymodifier_eventstate &
774 ~(keymodifier_l | keymodifier_r);
775 const uint8_t keymodifier_sided[2] = {
776 uint8_t(keymodifier_l | keymodifier_unhandled),
777 keymodifier_r,
778 };
779 GHOST_TEventKeyData kdata{};
780 kdata.key = GHOST_kKeyUnknown;
781 kdata.utf8_buf[0] = '\0';
782 kdata.is_repeat = false;
783 for (int i = 0; i < ARRAY_SIZE(g_modifier_table); i++) {
784 if (keymodifier_eventstate & g_modifier_table[i].flag) {
785 for (int side = 0; side < 2; side++) {
786 if ((keymodifier_sided[side] & g_modifier_table[i].flag) == 0) {
787 kdata.key = g_modifier_table[i].ghost_key_pair[side];
788 wm_event_add_ghostevent(wm, win, GHOST_kEventKeyUp, &kdata, event_time_ms);
789 }
790 }
791 }
792 }
793 }
794}
795
797{
798 /* Update mouse position when a window is activated. */
799 int xy[2];
800 if (wm_cursor_position_get(win, &xy[0], &xy[1])) {
802 }
803}
804
806{
807 if (win->eventstate) {
808 return;
809 }
810
811 win->eventstate = MEM_callocN<wmEvent>("window event state");
813}
814
816
817/* Belongs to below. */
819 const char *title,
820 wmWindow *win,
821 bool is_dialog)
822{
823 /* A new window is created when page-flip mode is required for a window. */
824 GHOST_GPUSettings gpuSettings = {0};
826 gpuSettings.flags |= GHOST_gpuStereoVisual;
827 }
828
829 if (G.debug & G_DEBUG_GPU) {
830 gpuSettings.flags |= GHOST_gpuDebugContext;
831 }
832
834 gpuSettings.context_type = wm_ghost_drawing_context_type(gpu_backend);
835 gpuSettings.preferred_device.index = U.gpu_preferred_index;
836 gpuSettings.preferred_device.vendor_id = U.gpu_preferred_vendor_id;
837 gpuSettings.preferred_device.device_id = U.gpu_preferred_device_id;
838
839 int posx = 0;
840 int posy = 0;
841
843 blender::int2 scr_size;
844 if (wm_get_desktopsize(scr_size)) {
845 posx = win->posx;
846 posy = (scr_size[1] - win->posy - win->sizey);
847 }
848 }
849
850 /* Clear drawable so we can set the new window. */
851 wmWindow *prev_windrawable = wm->windrawable;
853
854 GHOST_WindowHandle ghostwin = GHOST_CreateWindow(
855 g_system,
856 static_cast<GHOST_WindowHandle>((win->parent) ? win->parent->ghostwin : nullptr),
857 title,
858 posx,
859 posy,
860 win->sizex,
861 win->sizey,
863 is_dialog,
864 gpuSettings);
865
866 if (ghostwin) {
867 win->gpuctx = GPU_context_create(ghostwin, nullptr);
869
870 /* Needed so we can detect the graphics card below. */
871 GPU_init();
872
873 /* Set window as drawable upon creation. Note this has already been
874 * it has already been activated by GHOST_CreateWindow. */
875 wm_window_set_drawable(wm, win, false);
876
877 win->ghostwin = ghostwin;
878 GHOST_SetWindowUserData(ghostwin, win); /* Pointer back. */
879
881
882 /* Store actual window size in blender window. */
883 /* WIN32: gives undefined window size when minimized. */
884 if (GHOST_GetWindowState(static_cast<GHOST_WindowHandle>(win->ghostwin)) !=
886 {
888 }
889
890#ifndef __APPLE__
891 /* Set the state here, so minimized state comes up correct on windows. */
892 if (wm_init_state.window_focus) {
894 }
895#endif
896
897 /* Get the window background color from the current theme. Using the top-bar header
898 * background theme color to match with the colored title-bar decoration style. */
899 float window_bg_color[3];
901 UI_GetThemeColor3fv(TH_BACK, window_bg_color);
902
903 /* Until screens get drawn, draw a default background using the window theme color. */
904 GPU_clear_color(window_bg_color[0], window_bg_color[1], window_bg_color[2], 1.0f);
905
906 /* Needed here, because it's used before it reads #UserDef. */
908
910
911 /* Clear double buffer to avoids flickering of new windows on certain drivers, see #97600. */
912 GPU_clear_color(window_bg_color[0], window_bg_color[1], window_bg_color[2], 1.0f);
913
915 }
916 else {
917 wm_window_set_drawable(wm, prev_windrawable, false);
918 }
919}
920
921static void wm_window_ghostwindow_ensure(wmWindowManager *wm, wmWindow *win, bool is_dialog)
922{
923 if (win->ghostwin == nullptr) {
924 if ((win->sizex == 0) || (wm_init_state.override_flag & WIN_OVERRIDE_GEOM)) {
925 win->posx = wm_init_state.start[0];
926 win->posy = wm_init_state.start[1];
927 win->sizex = wm_init_state.size[0];
928 win->sizey = wm_init_state.size[1];
929
930 if (wm_init_state.override_flag & WIN_OVERRIDE_GEOM) {
932 wm_init_state.override_flag &= ~WIN_OVERRIDE_GEOM;
933 }
934 else {
936 }
937 }
938
939 if (wm_init_state.override_flag & WIN_OVERRIDE_WINSTATE) {
940 win->windowstate = wm_init_state.windowstate;
941 wm_init_state.override_flag &= ~WIN_OVERRIDE_WINSTATE;
942 }
943
944 /* Without this, cursor restore may fail, see: #45456. */
945 if (win->cursor == 0) {
947 }
948
949 wm_window_ghostwindow_add(wm, "Blender", win, is_dialog);
950 }
951
952 if (win->ghostwin != nullptr) {
953 /* If we have no `ghostwin` this is a buggy window that should be removed.
954 * However we still need to initialize it correctly so the screen doesn't hang. */
955
956 /* Happens after file-read. */
958
960
962 /* Only decoration style we have for now. */
965 }
966 }
967
968 /* Add key-map handlers (1 handler for all keys in map!). */
971
974
975 keymap = WM_keymap_ensure(wm->defaultconf, "Screen Editing", SPACE_EMPTY, RGN_TYPE_WINDOW);
977
978 /* Add drop boxes. */
979 {
982 }
983 WM_window_title(wm, win);
984
985 /* Add top-bar. */
987}
988
990{
991 BLI_assert(G.background == false);
992
993 /* No command-line prefsize? then we set this.
994 * Note that these values will be used only
995 * when there is no startup.blend yet.
996 */
997 if (wm_init_state.size[0] == 0) {
999 /* Use fallback values. */
1000 wm_init_state.size = blender::int2(0);
1001 }
1002
1003 /* NOTE: this isn't quite correct, active screen maybe offset 1000s if PX,
1004 * we'd need a #wm_get_screensize like function that gives offset,
1005 * in practice the window manager will likely move to the correct monitor. */
1006 wm_init_state.start = blender::int2(0);
1007 }
1008
1009 LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
1010 wm_window_ghostwindow_ensure(wm, win, false);
1011 }
1012}
1013
1015{
1016 BLI_assert(G.background == false);
1017
1019 if (win->ghostwin == nullptr) {
1020 wm_window_close(C, wm, win);
1021 }
1022 }
1023}
1024
1025/* Update window size and position based on data from GHOST window. */
1027{
1028 GHOST_RectangleHandle client_rect = GHOST_GetClientBounds(
1029 static_cast<GHOST_WindowHandle>(win->ghostwin));
1030 int l, t, r, b;
1031 GHOST_GetRectangle(client_rect, &l, &t, &r, &b);
1032
1033 GHOST_DisposeRectangle(client_rect);
1034
1035 int sizex = r - l;
1036 int sizey = b - t;
1037
1038 int posx = 0;
1039 int posy = 0;
1040
1042 blender::int2 scr_size;
1043 if (wm_get_desktopsize(scr_size)) {
1044 posx = l;
1045 posy = scr_size[1] - t - win->sizey;
1046 }
1047 }
1048
1049 if (win->sizex != sizex || win->sizey != sizey || win->posx != posx || win->posy != posy) {
1050 win->sizex = sizex;
1051 win->sizey = sizey;
1052 win->posx = posx;
1053 win->posy = posy;
1054 return true;
1055 }
1056 return false;
1057}
1058
1060 const char *title,
1061 const rcti *rect_unscaled,
1062 int space_type,
1063 bool toplevel,
1064 bool dialog,
1065 bool temp,
1066 eWindowAlignment alignment,
1067 void (*area_setup_fn)(bScreen *screen, ScrArea *area, void *user_data),
1068 void *area_setup_user_data)
1069{
1070 Main *bmain = CTX_data_main(C);
1072 wmWindow *win_prev = CTX_wm_window(C);
1073 Scene *scene = CTX_data_scene(C);
1074 ViewLayer *view_layer = CTX_data_view_layer(C);
1075 int x = rect_unscaled->xmin;
1076 int y = rect_unscaled->ymin;
1077 /* Duplicated windows are created at Area size, so duplicated
1078 * minimized areas can init at 2 pixels high before being
1079 * resized at the end of window creation. Therefore minimums. */
1080 int sizex = std::max(BLI_rcti_size_x(rect_unscaled), 200);
1081 int sizey = std::max(BLI_rcti_size_y(rect_unscaled), 150);
1082 rcti rect;
1083
1084 const float native_pixel_size = GHOST_GetNativePixelSize(
1085 static_cast<GHOST_WindowHandle>(win_prev->ghostwin));
1086 /* Convert to native OS window coordinates. */
1087 rect.xmin = win_prev->posx + (x / native_pixel_size);
1088 rect.ymin = win_prev->posy + (y / native_pixel_size);
1089 sizex /= native_pixel_size;
1090 sizey /= native_pixel_size;
1091
1092 if (alignment == WIN_ALIGN_LOCATION_CENTER) {
1093 /* Window centered around x,y location. */
1094 rect.xmin -= sizex / 2;
1095 rect.ymin -= sizey / 2;
1096 }
1097 else if (alignment == WIN_ALIGN_PARENT_CENTER) {
1098 /* Centered within parent. X,Y as offsets from there. */
1099 rect.xmin += (win_prev->sizex - sizex) / 2;
1100 rect.ymin += (win_prev->sizey - sizey) / 2;
1101 }
1102 else {
1103 /* Positioned absolutely within parent bounds. */
1104 }
1105
1106 rect.xmax = rect.xmin + sizex;
1107 rect.ymax = rect.ymin + sizey;
1108
1109 /* Changes rect to fit within desktop. */
1110 wm_window_check_size(&rect);
1111
1112 /* Reuse temporary windows when they share the same single area. */
1113 wmWindow *win = nullptr;
1114 if (temp) {
1115 LISTBASE_FOREACH (wmWindow *, win_iter, &wm->windows) {
1116 const bScreen *screen = WM_window_get_active_screen(win_iter);
1117 if (screen && screen->temp && BLI_listbase_is_single(&screen->areabase)) {
1118 ScrArea *area = static_cast<ScrArea *>(screen->areabase.first);
1119 if (space_type == (area->butspacetype ? area->butspacetype : area->spacetype)) {
1120 win = win_iter;
1121 break;
1122 }
1123 }
1124 }
1125 }
1126
1127 /* Add new window? */
1128 if (win == nullptr) {
1129 win = wm_window_new(bmain, wm, toplevel ? nullptr : win_prev, dialog);
1130 win->posx = rect.xmin;
1131 win->posy = rect.ymin;
1132 win->sizex = BLI_rcti_size_x(&rect);
1133 win->sizey = BLI_rcti_size_y(&rect);
1134 *win->stereo3d_format = *win_prev->stereo3d_format;
1135 }
1136
1137 bScreen *screen = WM_window_get_active_screen(win);
1138
1139 if (WM_window_get_active_workspace(win) == nullptr) {
1140 WorkSpace *workspace = WM_window_get_active_workspace(win_prev);
1142 }
1143
1144 if (screen == nullptr) {
1145 /* Add new screen layout. */
1146 WorkSpace *workspace = WM_window_get_active_workspace(win);
1147 WorkSpaceLayout *layout = ED_workspace_layout_add(bmain, workspace, win, "temp");
1148
1149 screen = BKE_workspace_layout_screen_get(layout);
1150 WM_window_set_active_layout(win, workspace, layout);
1151 }
1152
1153 /* Set scene and view layer to match original window. */
1154 STRNCPY(win->view_layer_name, view_layer->name);
1155 if (WM_window_get_active_scene(win) != scene) {
1156 /* No need to refresh the tool-system as the window has not yet finished being setup. */
1157 ED_screen_scene_change(C, win, scene, false);
1158 }
1159
1160 screen->temp = temp;
1161
1162 /* Make window active, and validate/resize. */
1163 CTX_wm_window_set(C, win);
1164 const bool new_window = (win->ghostwin == nullptr);
1165 if (new_window) {
1166 wm_window_ghostwindow_ensure(wm, win, dialog);
1167 }
1168 WM_check(C);
1169
1170 /* It's possible `win->ghostwin == nullptr`.
1171 * instead of attempting to cleanup here (in a half finished state),
1172 * finish setting up the screen, then free it at the end of the function,
1173 * to avoid having to take into account a partially-created window.
1174 */
1175
1176 if (area_setup_fn) {
1177 /* When the caller is setting up the area, it should always be empty
1178 * because it's expected the callback sets the type. */
1179 BLI_assert(space_type == SPACE_EMPTY);
1180 /* NOTE(@ideasman42): passing in a callback to setup the `area` is admittedly awkward.
1181 * This is done so #ED_screen_refresh has a valid area to initialize,
1182 * otherwise it will attempt to make the empty area usable via #ED_area_init.
1183 * While refreshing the window could be postponed this makes the state of the
1184 * window less predictable to the caller. */
1185 ScrArea *area = static_cast<ScrArea *>(screen->areabase.first);
1186 area_setup_fn(screen, area, area_setup_user_data);
1187 CTX_wm_area_set(C, area);
1188 }
1189 else if (space_type != SPACE_EMPTY) {
1190 /* Ensure it shows the right space-type editor. */
1191 ScrArea *area = static_cast<ScrArea *>(screen->areabase.first);
1192 CTX_wm_area_set(C, area);
1193 ED_area_newspace(C, area, space_type, false);
1194 }
1195
1196 ED_screen_change(C, screen);
1197
1198 if (!new_window) {
1199 /* Set size in GHOST window and then update size and position from GHOST,
1200 * in case they where changed by GHOST to fit the monitor/screen. */
1201 wm_window_set_size(win, win->sizex, win->sizey);
1203 }
1204
1205 /* Refresh screen dimensions, after the effective window size is known. */
1206 ED_screen_refresh(C, wm, win);
1207
1208 if (win->ghostwin) {
1209 wm_window_raise(win);
1210 WM_window_title(wm, win, title);
1211 return win;
1212 }
1213
1214 /* Very unlikely! but opening a new window can fail. */
1215 wm_window_close(C, wm, win);
1216 CTX_wm_window_set(C, win_prev);
1217
1218 return nullptr;
1219}
1220
1222
1223/* -------------------------------------------------------------------- */
1226
1234
1236{
1237 wmWindow *win_src = CTX_wm_window(C);
1239 const rcti window_rect = {
1240 /*xmin*/ 0,
1241 /*xmax*/ int(win_src->sizex * 0.95f),
1242 /*ymin*/ 0,
1243 /*ymax*/ int(win_src->sizey * 0.9f),
1244 };
1245
1246 bool ok = (WM_window_open(C,
1247 nullptr,
1248 &window_rect,
1249 area->spacetype,
1250 false,
1251 false,
1252 false,
1254 nullptr,
1255 nullptr) != nullptr);
1256
1257 if (!ok) {
1258 BKE_report(op->reports, RPT_ERROR, "Failed to create window");
1259 return OPERATOR_CANCELLED;
1260 }
1261 return OPERATOR_FINISHED;
1262}
1263
1265{
1266 wmWindow *win_src = CTX_wm_window(C);
1267
1268 bool ok = (wm_window_copy_test(C, win_src, true, false) != nullptr);
1269 if (!ok) {
1270 BKE_report(op->reports, RPT_ERROR, "Failed to create window");
1271 return OPERATOR_CANCELLED;
1272 }
1273 return OPERATOR_FINISHED;
1274}
1275
1277{
1278 wmWindow *window = CTX_wm_window(C);
1279
1280 if (G.background) {
1281 return OPERATOR_CANCELLED;
1282 }
1283
1285 static_cast<GHOST_WindowHandle>(window->ghostwin));
1287 GHOST_SetWindowState(static_cast<GHOST_WindowHandle>(window->ghostwin),
1289 }
1290 else {
1291 GHOST_SetWindowState(static_cast<GHOST_WindowHandle>(window->ghostwin),
1293 }
1294
1295 return OPERATOR_FINISHED;
1296}
1297
1299
1300/* -------------------------------------------------------------------- */
1303
1305{
1306 float fac = GHOST_GetNativePixelSize(static_cast<GHOST_WindowHandle>(win->ghostwin));
1307 *x *= fac;
1308
1309 *y = (win->sizey - 1) - *y;
1310 *y *= fac;
1311}
1312
1314{
1315 float fac = GHOST_GetNativePixelSize(static_cast<GHOST_WindowHandle>(win->ghostwin));
1316
1317 *x /= fac;
1318 *y /= fac;
1319 *y = win->sizey - *y - 1;
1320}
1321
1323{
1324 GHOST_ScreenToClient(static_cast<GHOST_WindowHandle>(win->ghostwin), *x, *y, x, y);
1326}
1327
1329{
1331 GHOST_ClientToScreen(static_cast<GHOST_WindowHandle>(win->ghostwin), *x, *y, x, y);
1332}
1333
1334bool wm_cursor_position_get(wmWindow *win, int *r_x, int *r_y)
1335{
1336 if (UNLIKELY(G.f & G_FLAG_EVENT_SIMULATE)) {
1337 *r_x = win->eventstate->xy[0];
1338 *r_y = win->eventstate->xy[1];
1339 return true;
1340 }
1341
1343 g_system, static_cast<GHOST_WindowHandle>(win->ghostwin), r_x, r_y) == GHOST_kSuccess)
1344 {
1346 return true;
1347 }
1348
1349 return false;
1350}
1351
1353static uint8_t wm_ghost_modifier_query(const enum ModSide side)
1354{
1355 uint8_t result = 0;
1356 for (int i = 0; i < ARRAY_SIZE(g_modifier_table); i++) {
1357 bool val = false;
1359 if (val) {
1360 result |= g_modifier_table[i].flag;
1361 }
1362 }
1363 return result;
1364}
1365
1367{
1368 BLI_assert(ELEM(wm->windrawable, nullptr, win));
1369
1370 wm->windrawable = win;
1371 if (activate) {
1372 GHOST_ActivateWindowDrawingContext(static_cast<GHOST_WindowHandle>(win->ghostwin));
1373 }
1374 GPU_context_active_set(static_cast<GPUContext *>(win->gpuctx));
1375}
1376
1378{
1379 if (wm->windrawable) {
1380 wm->windrawable = nullptr;
1381 }
1382}
1383
1385{
1387
1388 if (win != wm->windrawable && win->ghostwin) {
1389 // win->lmbut = 0; /* Keeps hanging when mouse-pressed while other window opened. */
1391
1392 if (G.debug & G_DEBUG_EVENTS) {
1393 printf("%s: set drawable %d\n", __func__, win->winid);
1394 }
1395
1396 wm_window_set_drawable(wm, win, true);
1397 }
1398
1399 if (win->ghostwin) {
1400 /* This can change per window. */
1401 WM_window_set_dpi(win);
1402 }
1403}
1404
1406{
1409 wmWindowManager *wm = static_cast<wmWindowManager *>(G_MAIN->wm.first);
1410
1411 if (wm == nullptr) {
1412 return;
1413 }
1414 wmWindow *win = wm->windrawable;
1415
1416 if (win && win->ghostwin) {
1418 wm_window_set_drawable(wm, win, true);
1419 }
1420}
1421
1422#ifndef NDEBUG
1427static void ghost_event_proc_timestamp_warning(GHOST_EventHandle ghost_event)
1428{
1429 /* NOTE: The following time constants can be tweaked if they're reporting false positives. */
1430
1431 /* The reference event time-stamp must have happened in this time-frame. */
1432 constexpr uint64_t event_time_ok_ms = 1000;
1433 /* The current event time-stamp must be outside this time-frame to be considered an error. */
1434 constexpr uint64_t event_time_error_ms = 5000;
1435
1436 static uint64_t event_ms_ref_last = std::numeric_limits<uint64_t>::max();
1437 const uint64_t event_ms = GHOST_GetEventTime(ghost_event);
1438 const uint64_t event_ms_ref = event_ms_ref_last;
1439
1440 /* Assign first (allow early returns). */
1441 event_ms_ref_last = event_ms;
1442
1443 if (event_ms_ref == std::numeric_limits<uint64_t>::max()) {
1444 return;
1445 }
1446 /* Check the events are recent enough to be used for testing. */
1447 const uint64_t now_ms = GHOST_GetMilliSeconds(g_system);
1448 /* Ensure the reference time occurred in the last #event_time_ok_ms.
1449 * If not, the reference time it's self may be a bad time-stamp. */
1450 if (event_ms_ref < event_time_error_ms || (event_ms_ref < (now_ms - event_time_ok_ms)) ||
1451 (event_ms_ref > (now_ms + event_time_ok_ms)))
1452 {
1453 /* Skip, the reference time not recent enough to be used. */
1454 return;
1455 }
1456
1457 /* NOTE: Regarding time-stamps from the future.
1458 * Generally this shouldn't happen but may do depending on the kinds of events.
1459 * Different input methods may detect and trigger events in a way that wont ensure
1460 * monotonic event times, so only consider this an error for large time deltas. */
1461 double time_delta = 0.0;
1462 if (event_ms < (event_ms_ref - event_time_error_ms)) {
1463 /* New event time is after (to be expected). */
1464 time_delta = double(now_ms - event_ms) / -1000.0;
1465 }
1466 else if (event_ms > (event_ms_ref + event_time_error_ms)) {
1467 /* New event time is before (unexpected but not an error). */
1468 time_delta = double(event_ms - now_ms) / 1000.0;
1469 }
1470 else {
1471 /* Time is in range. */
1472 return;
1473 }
1474
1475 const char *time_unit = "seconds";
1476 const struct {
1477 const char *unit;
1478 double scale;
1479 } unit_table[] = {{"minutes", 60}, {"hours", 60}, {"days", 24}, {"weeks", 7}, {"years", 52}};
1480 for (int i = 0; i < ARRAY_SIZE(unit_table); i++) {
1481 if (std::abs(time_delta) <= unit_table[i].scale) {
1482 break;
1483 }
1484 time_delta /= unit_table[i].scale;
1485 time_unit = unit_table[i].unit;
1486 }
1487
1488 fprintf(stderr,
1489 "GHOST: suspicious time-stamp from far in the %s: %.2f %s, "
1490 "absolute value is %" PRIu64 ", current time is %" PRIu64 ", for type %d\n",
1491 time_delta < 0.0f ? "past" : "future",
1492 std::abs(time_delta),
1493 time_unit,
1494 event_ms,
1495 now_ms,
1496 int(GHOST_GetEventType(ghost_event)));
1497}
1498#endif /* !NDEBUG */
1499
1505static bool ghost_event_proc(GHOST_EventHandle ghost_event, GHOST_TUserDataPtr C_void_ptr)
1506{
1507 bContext *C = static_cast<bContext *>(C_void_ptr);
1509 GHOST_TEventType type = GHOST_GetEventType(ghost_event);
1510
1511 GHOST_WindowHandle ghostwin = GHOST_GetEventWindow(ghost_event);
1512
1513#ifndef NDEBUG
1515#endif
1516
1517 if (type == GHOST_kEventQuitRequest) {
1518 /* Find an active window to display quit dialog in. */
1519 wmWindow *win;
1520 if (ghostwin && GHOST_ValidWindow(g_system, ghostwin)) {
1521 win = static_cast<wmWindow *>(GHOST_GetWindowUserData(ghostwin));
1522 }
1523 else {
1524 win = wm->winactive;
1525 }
1526
1527 /* Display quit dialog or quit immediately. */
1528 if (win) {
1530 }
1531 else {
1533 }
1534 return true;
1535 }
1536
1538 const uint64_t event_time_ms = GHOST_GetEventTime(ghost_event);
1539
1540 /* Ghost now can call this function for life resizes,
1541 * but it should return if WM didn't initialize yet.
1542 * Can happen on file read (especially full size window). */
1543 if ((wm->init_flag & WM_INIT_FLAG_WINDOW) == 0) {
1544 return true;
1545 }
1546 if (!ghostwin) {
1547 /* XXX: should be checked, why are we getting an event here, and what is it? */
1548 puts("<!> event has no window");
1549 return true;
1550 }
1551 if (!GHOST_ValidWindow(g_system, ghostwin)) {
1552 /* XXX: should be checked, why are we getting an event here, and what is it? */
1553 puts("<!> event has invalid window");
1554 return true;
1555 }
1556
1557 wmWindow *win = static_cast<wmWindow *>(GHOST_GetWindowUserData(ghostwin));
1558
1559 switch (type) {
1561 wm_window_update_eventstate_modifiers_clear(wm, win, event_time_ms);
1562
1563 wm_event_add_ghostevent(wm, win, type, data, event_time_ms);
1564 win->active = 0;
1565 break;
1566 }
1568 /* Ensure the event state matches modifiers (window was inactive). */
1569 wm_window_update_eventstate_modifiers(wm, win, event_time_ms);
1570
1571 /* Entering window, update mouse position (without sending an event). */
1573
1574 /* No context change! `C->wm->windrawable` is drawable, or for area queues. */
1575 wm->winactive = win;
1576 win->active = 1;
1577
1578 /* Zero the `keymodifier`, it hangs on hotkeys that open windows otherwise. */
1580
1581 win->addmousemove = 1; /* Enables highlighted buttons. */
1582
1583 wm_window_make_drawable(wm, win);
1584
1585 /* NOTE(@sergey): Window might be focused by mouse click in configuration of window manager
1586 * when focus is not following mouse
1587 * click could have been done on a button and depending on window manager settings
1588 * click would be passed to blender or not, but in any case button under cursor
1589 * should be activated, so at max next click on button without moving mouse
1590 * would trigger its handle function
1591 * currently it seems to be common practice to generate new event for, but probably
1592 * we'll need utility function for this?
1593 */
1594 wmEvent event;
1595 wm_event_init_from_window(win, &event);
1596 event.type = MOUSEMOVE;
1597 event.val = KM_NOTHING;
1598 copy_v2_v2_int(event.prev_xy, event.xy);
1599 event.flag = eWM_EventFlag(0);
1600
1601 WM_event_add(win, &event);
1602
1603 break;
1604 }
1606 wm_window_close(C, wm, win);
1607 break;
1608 }
1610 if (G.debug & G_DEBUG_EVENTS) {
1611 printf("%s: ghost redraw %d\n", __func__, win->winid);
1612 }
1613
1614 wm_window_make_drawable(wm, win);
1615 WM_event_add_notifier_ex(wm, win, NC_WINDOW, nullptr);
1616
1617 break;
1618 }
1620 if (G.debug & G_DEBUG_EVENTS) {
1621 printf("%s: ghost redraw decor %d\n", __func__, win->winid);
1622 }
1623
1624 wm_window_make_drawable(wm, win);
1625#if 0
1626 /* NOTE(@ideasman42): Ideally we could swap-buffers to avoid a full redraw.
1627 * however this causes window flickering on resize with LIBDECOR under WAYLAND. */
1629#else
1630 WM_event_add_notifier_ex(wm, win, NC_WINDOW, nullptr);
1631#endif
1632
1633 break;
1634 }
1638 static_cast<GHOST_WindowHandle>(win->ghostwin));
1639 win->windowstate = state;
1640
1641 WM_window_set_dpi(win);
1642
1643 /* WIN32: gives undefined window size when minimized. */
1645 /*
1646 * Ghost sometimes send size or move events when the window hasn't changed.
1647 * One case of this is using COMPIZ on Linux.
1648 * To alleviate the problem we ignore all such event here.
1649 *
1650 * It might be good to eventually do that at GHOST level, but that is for another time.
1651 */
1653 const bScreen *screen = WM_window_get_active_screen(win);
1654
1655 /* Debug prints. */
1656 if (G.debug & G_DEBUG_EVENTS) {
1657 const char *state_str;
1658 state = GHOST_GetWindowState(static_cast<GHOST_WindowHandle>(win->ghostwin));
1659
1661 state_str = "normal";
1662 }
1663 else if (state == GHOST_kWindowStateMinimized) {
1664 state_str = "minimized";
1665 }
1666 else if (state == GHOST_kWindowStateMaximized) {
1667 state_str = "maximized";
1668 }
1669 else if (state == GHOST_kWindowStateFullScreen) {
1670 state_str = "full-screen";
1671 }
1672 else {
1673 state_str = "<unknown>";
1674 }
1675
1676 printf("%s: window %d state = %s\n", __func__, win->winid, state_str);
1677
1678 if (type != GHOST_kEventWindowSize) {
1679 printf("win move event pos %d %d size %d %d\n",
1680 win->posx,
1681 win->posy,
1682 win->sizex,
1683 win->sizey);
1684 }
1685 }
1686
1687 wm_window_make_drawable(wm, win);
1688 BKE_icon_changed(screen->id.icon_id);
1689 WM_event_add_notifier_ex(wm, win, NC_SCREEN | NA_EDITED, nullptr);
1690 WM_event_add_notifier_ex(wm, win, NC_WINDOW | NA_EDITED, nullptr);
1691
1692#if defined(__APPLE__) || defined(WIN32)
1693 /* MACOS and WIN32 don't return to the main-loop while resize. */
1694 int dummy_sleep_ms = 0;
1695 wm_window_timers_process(C, &dummy_sleep_ms);
1699#endif
1700 }
1701 }
1702 break;
1703 }
1704
1706 WM_window_set_dpi(win);
1707 /* Font's are stored at each DPI level, without this we can easy load 100's of fonts. */
1709
1710 WM_main_add_notifier(NC_WINDOW, nullptr); /* Full redraw. */
1711 WM_main_add_notifier(NC_SCREEN | NA_EDITED, nullptr); /* Refresh region sizes. */
1712 break;
1713 }
1714
1716 const char *path = static_cast<const char *>(data);
1717
1718 if (path) {
1719 wmOperatorType *ot = WM_operatortype_find("WM_OT_open_mainfile", false);
1720 /* Operator needs a valid window in context, ensures it is correctly set. */
1721 CTX_wm_window_set(C, win);
1722
1723 PointerRNA props_ptr;
1725 RNA_string_set(&props_ptr, "filepath", path);
1726 RNA_boolean_set(&props_ptr, "display_file_selector", false);
1727 WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &props_ptr, nullptr);
1728 WM_operator_properties_free(&props_ptr);
1729
1730 CTX_wm_window_set(C, nullptr);
1731 }
1732 break;
1733 }
1735 const GHOST_TEventDragnDropData *ddd = static_cast<const GHOST_TEventDragnDropData *>(data);
1736
1737 /* Ensure the event state matches modifiers (window was inactive). */
1738 wm_window_update_eventstate_modifiers(wm, win, event_time_ms);
1739 /* Entering window, update mouse position (without sending an event). */
1741
1742 wmEvent event;
1743 wm_event_init_from_window(win, &event); /* Copy last state, like mouse coords. */
1744
1745 /* Activate region. */
1746 event.type = MOUSEMOVE;
1747 event.val = KM_NOTHING;
1748 copy_v2_v2_int(event.prev_xy, event.xy);
1749
1750 copy_v2_v2_int(event.xy, &ddd->x);
1751 wm_cursor_position_from_ghost_screen_coords(win, &event.xy[0], &event.xy[1]);
1752
1753 /* The values from #wm_window_update_eventstate may not match (under WAYLAND they don't)
1754 * Write this into the event state. */
1755 copy_v2_v2_int(win->eventstate->xy, event.xy);
1756
1757 event.flag = eWM_EventFlag(0);
1758
1759 /* No context change! `C->wm->windrawable` is drawable, or for area queues. */
1760 wm->winactive = win;
1761 win->active = 1;
1762
1763 WM_event_add(win, &event);
1764
1765 /* Make blender drop event with custom data pointing to wm drags. */
1766 event.type = EVT_DROP;
1767 event.val = KM_RELEASE;
1768 event.custom = EVT_DATA_DRAGDROP;
1769 event.customdata = &wm->drags;
1770 event.customdata_free = true;
1771
1772 WM_event_add(win, &event);
1773
1774 // printf("Drop detected\n");
1775
1776 /* Add drag data to wm for paths. */
1777
1779 const GHOST_TStringArray *stra = static_cast<const GHOST_TStringArray *>(ddd->data);
1780
1781 if (stra->count) {
1782 CLOG_INFO(WM_LOG_EVENTS, 1, "Drop %d files:", stra->count);
1783 for (const char *path : blender::Span((char **)stra->strings, stra->count)) {
1784 CLOG_INFO(WM_LOG_EVENTS, 1, "%s", path);
1785 }
1786 /* Try to get icon type from extension of the first path. */
1787 int icon = ED_file_extension_icon((char *)stra->strings[0]);
1789 blender::Span((char **)stra->strings, stra->count));
1790 WM_event_start_drag(C, icon, WM_DRAG_PATH, path_data, WM_DRAG_NOP);
1791 /* Void pointer should point to string, it makes a copy. */
1792 }
1793 }
1794 else if (ddd->dataType == GHOST_kDragnDropTypeString) {
1795 /* Drop an arbitrary string. */
1796 std::string *str = MEM_new<std::string>(__func__, static_cast<const char *>(ddd->data));
1798 }
1799
1800 break;
1801 }
1803 /* Only update if the actual pixel size changes. */
1804 float prev_pixelsize = U.pixelsize;
1805 WM_window_set_dpi(win);
1806
1807 if (U.pixelsize != prev_pixelsize) {
1809
1810 /* Close all popups since they are positioned with the pixel
1811 * size baked in and it's difficult to correct them. */
1812 CTX_wm_window_set(C, win);
1814 CTX_wm_window_set(C, nullptr);
1815
1816 wm_window_make_drawable(wm, win);
1817
1818 WM_event_add_notifier_ex(wm, win, NC_SCREEN | NA_EDITED, nullptr);
1819 WM_event_add_notifier_ex(wm, win, NC_WINDOW | NA_EDITED, nullptr);
1820 }
1821
1822 break;
1823 }
1825 case GHOST_kEventButtonUp: {
1826 if (win->active == 0) {
1827 /* Entering window, update cursor/tablet state & modifiers.
1828 * (ghost sends win-activate *after* the mouse-click in window!). */
1829 wm_window_update_eventstate_modifiers(wm, win, event_time_ms);
1831 }
1832
1833 wm_event_add_ghostevent(wm, win, type, data, event_time_ms);
1834 break;
1835 }
1836 default: {
1837 wm_event_add_ghostevent(wm, win, type, data, event_time_ms);
1838 break;
1839 }
1840 }
1841
1842 return true;
1843}
1844
1854static bool wm_window_timers_process(const bContext *C, int *sleep_us_p)
1855{
1856 Main *bmain = CTX_data_main(C);
1858 const double time = BLI_time_now_seconds();
1859 bool has_event = false;
1860
1861 const int sleep_us = *sleep_us_p;
1862 /* The nearest time an active timer is scheduled to run. */
1863 double ntime_min = DBL_MAX;
1864
1865 /* Mutable in case the timer gets removed. */
1867 if (wt->flags & WM_TIMER_TAGGED_FOR_REMOVAL) {
1868 continue;
1869 }
1870 if (wt->sleep == true) {
1871 continue;
1872 }
1873
1874 /* Future timer, update nearest time & skip. */
1875 if (wt->time_next >= time) {
1876 if ((has_event == false) && (sleep_us != 0)) {
1877 /* The timer is not ready to run but may run shortly. */
1878 ntime_min = std::min(wt->time_next, ntime_min);
1879 }
1880 continue;
1881 }
1882
1883 wt->time_delta = time - wt->time_last;
1884 wt->time_duration += wt->time_delta;
1885 wt->time_last = time;
1886
1887 wt->time_next = wt->time_start;
1888 if (wt->time_step != 0.0f) {
1889 wt->time_next += wt->time_step * ceil(wt->time_duration / wt->time_step);
1890 }
1891
1892 if (wt->event_type == TIMERJOBS) {
1893 wm_jobs_timer(wm, wt);
1894 }
1895 else if (wt->event_type == TIMERAUTOSAVE) {
1896 wm_autosave_timer(bmain, wm, wt);
1897 }
1898 else if (wt->event_type == TIMERNOTIFIER) {
1899 WM_main_add_notifier(POINTER_AS_UINT(wt->customdata), nullptr);
1900 }
1901 else if (wmWindow *win = wt->win) {
1902 wmEvent event;
1903 wm_event_init_from_window(win, &event);
1904
1905 event.type = wt->event_type;
1906 event.val = KM_NOTHING;
1907 event.keymodifier = EVENT_NONE;
1908 event.flag = eWM_EventFlag(0);
1909 event.custom = EVT_DATA_TIMER;
1910 event.customdata = wt;
1911 WM_event_add(win, &event);
1912
1913 has_event = true;
1914 }
1915 }
1916
1917 if ((has_event == false) && (sleep_us != 0) && (ntime_min != DBL_MAX)) {
1918 /* Clamp the sleep time so next execution runs earlier (if necessary).
1919 * Use `ceil` so the timer is guarantee to be ready to run (not always the case with rounding).
1920 * Even though using `floor` or `round` is more responsive,
1921 * it causes CPU intensive loops that may run until the timer is reached, see: #111579. */
1922 const double microseconds = 1000000.0;
1923 const double sleep_sec = double(sleep_us) / microseconds;
1924 const double sleep_sec_next = ntime_min - time;
1925
1926 if (sleep_sec_next < sleep_sec) {
1927 *sleep_us_p = int(std::ceil(sleep_sec_next * microseconds));
1928 }
1929 }
1930
1931 /* Effectively delete all timers marked for removal. */
1933
1934 return has_event;
1935}
1936
1938{
1941
1942 bool has_event = GHOST_ProcessEvents(g_system, false); /* `false` is no wait. */
1943
1944 if (has_event) {
1946 }
1947
1948 /* When there is no event, sleep 5 milliseconds not to use too much CPU when idle. */
1949 const int sleep_us_default = 5000;
1950 int sleep_us = has_event ? 0 : sleep_us_default;
1951 has_event |= wm_window_timers_process(C, &sleep_us);
1952#ifdef WITH_XR_OPENXR
1953 /* XR events don't use the regular window queues. So here we don't only trigger
1954 * processing/dispatching but also handling. */
1955 has_event |= wm_xr_events_handle(CTX_wm_manager(C));
1956#endif
1958
1959 /* Skip sleeping when simulating events so tests don't idle unnecessarily as simulated
1960 * events are typically generated from a timer that runs in the main loop. */
1961 if ((has_event == false) && (sleep_us != 0) && !(G.f & G_FLAG_EVENT_SIMULATE)) {
1962 if (sleep_us == sleep_us_default) {
1963 /* NOTE(@ideasman42): prefer #BLI_time_sleep_ms over `sleep_for(..)` in the common case
1964 * because this function uses lower resolution (millisecond) resolution sleep timers
1965 * which are tried & true for the idle loop. We could move to C++ `sleep_for(..)`
1966 * if this works well on all platforms but this needs further testing. */
1967 BLI_time_sleep_ms(sleep_us_default / 1000);
1968 }
1969 else {
1970 /* The time was shortened to resume for the upcoming timer, use a high resolution sleep.
1971 * Mainly happens during animation playback but could happen immediately before any timer.
1972 *
1973 * NOTE(@ideasman42): At time of writing Windows-10-22H2 doesn't give higher precision sleep.
1974 * Keep the functionality as it doesn't have noticeable down sides either. */
1975 std::this_thread::sleep_for(std::chrono::microseconds(sleep_us));
1976 }
1977 }
1978}
1979
1981
1982/* -------------------------------------------------------------------- */
1985
1987{
1988 if (g_system) {
1989 return;
1990 }
1991
1992 BLI_assert(C != nullptr);
1993 BLI_assert_msg(!G.background, "Use wm_ghost_init_background instead");
1994
1995 GHOST_EventConsumerHandle consumer;
1996
1998
2000
2003
2004 if (UNLIKELY(g_system == nullptr)) {
2005 /* GHOST will have reported the back-ends that failed to load. */
2006 fprintf(stderr, "GHOST: unable to initialize, exiting!\n");
2007 /* This will leak memory, it's preferable to crashing. */
2008 exit(EXIT_FAILURE);
2009 }
2010#if !(defined(WIN32) || defined(__APPLE__))
2012#endif
2013
2014 GHOST_Debug debug = {0};
2015 if (G.debug & G_DEBUG_GHOST) {
2016 debug.flags |= GHOST_kDebugDefault;
2017 }
2018 if (G.debug & G_DEBUG_WINTAB) {
2019 debug.flags |= GHOST_kDebugWintab;
2020 }
2022
2024
2025 if (wm_init_state.native_pixels) {
2027 }
2028
2029 GHOST_UseWindowFocus(wm_init_state.window_focus);
2030}
2031
2033{
2034 /* TODO: move this to `wm_init_exit.cc`. */
2035
2036 if (g_system) {
2037 return;
2038 }
2039
2041
2044
2045 GHOST_Debug debug = {0};
2046 if (G.debug & G_DEBUG_GHOST) {
2047 debug.flags |= GHOST_kDebugDefault;
2048 }
2050}
2051
2053{
2054 if (g_system) {
2056 }
2057 g_system = nullptr;
2058}
2059
2060const char *WM_ghost_backend()
2061{
2062#if !(defined(WIN32) || defined(__APPLE__))
2063 return g_system_backend_id ? g_system_backend_id : "NONE";
2064#else
2065 /* While this could be supported, at the moment it's only needed with GHOST X11/WAYLAND
2066 * to check which was selected and the API call may be removed after that's no longer needed.
2067 * Use dummy values to prevent this being used on other systems. */
2068 return g_system ? "DEFAULT" : "NONE";
2069#endif
2070}
2071
2073{
2074 switch (gpu_backend) {
2075 case GPU_BACKEND_NONE:
2077 case GPU_BACKEND_ANY:
2078 case GPU_BACKEND_OPENGL:
2079#ifdef WITH_OPENGL_BACKEND
2080 return GHOST_kDrawingContextTypeOpenGL;
2081#endif
2084 case GPU_BACKEND_VULKAN:
2085#ifdef WITH_VULKAN_BACKEND
2086 return GHOST_kDrawingContextTypeVulkan;
2087#endif
2090 case GPU_BACKEND_METAL:
2091#ifdef WITH_METAL_BACKEND
2092 return GHOST_kDrawingContextTypeMetal;
2093#endif
2096 }
2097
2098 /* Avoid control reaches end of non-void function compilation warning, which could be promoted
2099 * to error. */
2102}
2103
2105{
2106 uiBlock *block = UI_block_begin(
2107 C, region, "autorun_warning_popup", blender::ui::EmbossType::Emboss);
2110
2111 const char *title = RPT_("Python script uses OpenGL for drawing");
2112 const char *message1 = RPT_("This may lead to unexpected behavior");
2113 const char *message2 = RPT_(
2114 "One of the add-ons or scripts is using OpenGL and will not work correct on Metal");
2115 const char *message3 = RPT_(
2116 "Please contact the developer of the add-on to migrate to use 'gpu' module");
2117 const char *message4 = RPT_("See system tab in preferences to switch to OpenGL backend");
2118
2119 /* Measure strings to find the longest. */
2120 const uiStyle *style = UI_style_get_dpi();
2121 UI_fontstyle_set(&style->widget);
2122 int text_width = int(BLF_width(style->widget.uifont_id, title, BLF_DRAW_STR_DUMMY_MAX));
2123 text_width = std::max(text_width,
2124 int(BLF_width(style->widget.uifont_id, message1, BLF_DRAW_STR_DUMMY_MAX)));
2125 text_width = std::max(text_width,
2126 int(BLF_width(style->widget.uifont_id, message2, BLF_DRAW_STR_DUMMY_MAX)));
2127 text_width = std::max(text_width,
2128 int(BLF_width(style->widget.uifont_id, message3, BLF_DRAW_STR_DUMMY_MAX)));
2129 text_width = std::max(text_width,
2130 int(BLF_width(style->widget.uifont_id, message4, BLF_DRAW_STR_DUMMY_MAX)));
2131
2132 const int dialog_width = std::max(int(400.0f * UI_SCALE_FAC),
2133 text_width + int(style->columnspace * 2.5));
2134
2135 const short icon_size = 40 * UI_SCALE_FAC;
2136 uiLayout *layout = uiItemsAlertBox(
2137 block, style, dialog_width + icon_size, ALERT_ICON_ERROR, icon_size);
2138
2139 uiLayout *col = &layout->column(false);
2140 uiLayoutSetScaleY(col, 0.9f);
2141
2142 /* Title and explanation text. */
2143 uiItemL_ex(col, title, ICON_NONE, true, false);
2144 col->separator(0.8f, LayoutSeparatorType::Space);
2145
2146 uiLayout *messages = &col->column(false);
2147 uiLayoutSetScaleY(messages, 0.8f);
2148
2149 messages->label(message1, ICON_NONE);
2150 messages->label(message2, ICON_NONE);
2151 messages->label(message3, ICON_NONE);
2152 if (G.opengl_deprecation_usage_filename) {
2153 char location[1024];
2154 SNPRINTF(
2155 location, "%s:%d", G.opengl_deprecation_usage_filename, G.opengl_deprecation_usage_lineno);
2156 messages->label(location, ICON_NONE);
2157 }
2158 messages->label(message4, ICON_NONE);
2159
2160 col->separator(0.5f, LayoutSeparatorType::Space);
2161
2163
2164 return block;
2165}
2166
2168{
2169 static bool message_shown = false;
2170
2171 /* Exit when no failure detected. */
2172 if (!G.opengl_deprecation_usage_detected) {
2173 return;
2174 }
2175
2176 /* Have we already shown a message during this Blender session. `bgl` calls are done in a draw
2177 * handler that will run many times. */
2178 if (message_shown) {
2179 return;
2180 }
2181
2183 wmWindow *win = static_cast<wmWindow *>((wm->winactive) ? wm->winactive : wm->windows.first);
2184
2185 BKE_report(&wm->runtime->reports,
2186 RPT_ERROR,
2187 "One of the add-ons or scripts is using OpenGL and will not work correct on Metal. "
2188 "Please contact the developer of the add-on to migrate to use 'gpu' module");
2189
2190 if (win) {
2191 /* We want this warning on the Main window, not a child window even if active. See #118765. */
2192 if (win->parent) {
2193 win = win->parent;
2194 }
2195
2196 wmWindow *prevwin = CTX_wm_window(C);
2197 CTX_wm_window_set(C, win);
2199 CTX_wm_window_set(C, prevwin);
2200 }
2201
2202 message_shown = true;
2203}
2204
2206{
2207 uiBlock *block = UI_block_begin(
2208 C, region, "autorun_warning_popup", blender::ui::EmbossType::Emboss);
2211
2212 uiLayout *layout = uiItemsAlertBox(block, 44, ALERT_ICON_ERROR);
2213
2214 /* Title and explanation text. */
2215 uiLayout *col = &layout->column(false);
2216 uiLayoutSetScaleY(col, 0.8f);
2217 uiItemL_ex(
2218 col, RPT_("Failed to load using Vulkan, using OpenGL instead."), ICON_NONE, true, false);
2219 col->separator(1.3f, LayoutSeparatorType::Space);
2220
2221 col->label(RPT_("Updating GPU drivers may solve this issue."), ICON_NONE);
2222 col->label(RPT_("The graphics backend can be changed in the System section of the Preferences."),
2223 ICON_NONE);
2224
2226
2227 return block;
2228}
2229
2231{
2232 if (!bool(G.f & G_FLAG_GPU_BACKEND_FALLBACK)) {
2233 return;
2234 }
2235
2236 /* Have we already shown a message during this Blender session. */
2237 if (bool(G.f & G_FLAG_GPU_BACKEND_FALLBACK_QUIET)) {
2238 return;
2239 }
2241
2243 wmWindow *win = static_cast<wmWindow *>((wm->winactive) ? wm->winactive : wm->windows.first);
2244
2245 if (win) {
2246 /* We want this warning on the Main window, not a child window even if active. See #118765. */
2247 if (win->parent) {
2248 win = win->parent;
2249 }
2250
2251 wmWindow *prevwin = CTX_wm_window(C);
2252 CTX_wm_window_set(C, win);
2254 CTX_wm_window_set(C, prevwin);
2255 }
2256}
2257
2259{
2261 if (flag != 0) {
2262 return flag;
2263 }
2265
2266 /* NOTE(@ideasman42): Regarding tests.
2267 * Some callers of this function may run from tests where GHOST's hasn't been initialized.
2268 * In such cases it may be necessary to check `!G.background` which is acceptable in most cases.
2269 * At time of writing this is the case for `bl_animation_keyframing`.
2270 *
2271 * While this function *could* early-exit when in background mode, don't do this as GHOST
2272 * may be initialized in background mode for GPU rendering and in this case we may want to
2273 * query GHOST/GPU related capabilities. */
2274
2275 const GHOST_TCapabilityFlag ghost_flag = GHOST_GetCapabilities();
2276 if (ghost_flag & GHOST_kCapabilityCursorWarp) {
2278 }
2279 if (ghost_flag & GHOST_kCapabilityWindowPosition) {
2281 }
2282 if (ghost_flag & GHOST_kCapabilityPrimaryClipboard) {
2284 }
2285 if (ghost_flag & GHOST_kCapabilityGPUReadFrontBuffer) {
2287 }
2288 if (ghost_flag & GHOST_kCapabilityClipboardImages) {
2290 }
2291 if (ghost_flag & GHOST_kCapabilityDesktopSample) {
2293 }
2294 if (ghost_flag & GHOST_kCapabilityInputIME) {
2296 }
2299 }
2300 if (ghost_flag & GHOST_kCapabilityWindowDecorationStyles) {
2302 }
2303 if (ghost_flag & GHOST_kCapabilityKeyboardHyperKey) {
2305 }
2306
2307 return flag;
2308}
2309
2311
2312/* -------------------------------------------------------------------- */
2315
2316void WM_event_timer_sleep(wmWindowManager *wm, wmWindow * /*win*/, wmTimer *timer, bool do_sleep)
2317{
2318 /* Extra security check. */
2319 if (BLI_findindex(&wm->timers, timer) == -1) {
2320 return;
2321 }
2322 /* It's disputable if this is needed, when tagged for removal,
2323 * the sleep value won't be used anyway. */
2324 if (timer->flags & WM_TIMER_TAGGED_FOR_REMOVAL) {
2325 return;
2326 }
2327 timer->sleep = do_sleep;
2328}
2329
2331 wmWindow *win,
2332 const wmEventType event_type,
2333 const double time_step)
2334{
2335 BLI_assert(ISTIMER(event_type));
2336
2337 wmTimer *wt = MEM_callocN<wmTimer>("window timer");
2338 BLI_assert(time_step >= 0.0f);
2339
2340 wt->event_type = event_type;
2342 wt->time_next = wt->time_last + time_step;
2343 wt->time_start = wt->time_last;
2344 wt->time_step = time_step;
2345 wt->win = win;
2346
2347 BLI_addtail(&wm->timers, wt);
2348
2349 return wt;
2350}
2351
2353 wmWindow *win,
2354 const uint type,
2355 const double time_step)
2356{
2357 wmTimer *wt = MEM_callocN<wmTimer>("window timer");
2358 BLI_assert(time_step >= 0.0f);
2359
2362 wt->time_next = wt->time_last + time_step;
2363 wt->time_start = wt->time_last;
2364 wt->time_step = time_step;
2365 wt->win = win;
2366 wt->customdata = POINTER_FROM_UINT(type);
2368
2369 BLI_addtail(&wm->timers, wt);
2370
2371 return wt;
2372}
2373
2375{
2377 if ((wt->flags & WM_TIMER_TAGGED_FOR_REMOVAL) == 0) {
2378 continue;
2379 }
2380
2381 /* Actual removal and freeing of the timer. */
2382 BLI_remlink(&wm->timers, wt);
2383 MEM_freeN(wt);
2384 }
2385}
2386
2388{
2389 if (timer->customdata != nullptr && (timer->flags & WM_TIMER_NO_FREE_CUSTOM_DATA) == 0) {
2390 MEM_freeN(timer->customdata);
2391 timer->customdata = nullptr;
2392 }
2393}
2394
2396{
2398 "This should only be called when freeing the window-manager");
2399 while (wmTimer *timer = static_cast<wmTimer *>(BLI_pophead(&wm->timers))) {
2402 }
2403}
2404
2406{
2407 /* Extra security check. */
2408 if (BLI_findindex(&wm->timers, timer) == -1) {
2409 return;
2410 }
2411
2413
2414 /* Clear existing references to the timer. */
2415 if (wm->runtime->reports.reporttimer == timer) {
2416 wm->runtime->reports.reporttimer = nullptr;
2417 }
2418 /* There might be events in queue with this timer as customdata. */
2419 LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
2420 LISTBASE_FOREACH (wmEvent *, event, &win->runtime->event_queue) {
2421 if (event->customdata == timer) {
2422 event->customdata = nullptr;
2423 event->type = EVENT_NONE; /* Timer users customdata, don't want `nullptr == nullptr`. */
2424 }
2425 }
2426 }
2427
2428 /* Immediately free `customdata` if requested, so that invalid usages of that data after
2429 * calling `WM_event_timer_remove` can be easily spotted (through ASAN errors e.g.). */
2431}
2432
2434{
2435 timer->customdata = nullptr;
2436 WM_event_timer_remove(wm, win, timer);
2437}
2438
2440
2441/* -------------------------------------------------------------------- */
2448
2449struct {
2450 char *buffers[2];
2452
2454{
2455 if (g_wm_clipboard_text_simulate == nullptr) {
2456 return;
2457 }
2458 for (int i = 0; i < ARRAY_SIZE(g_wm_clipboard_text_simulate->buffers); i++) {
2459 char *buf = g_wm_clipboard_text_simulate->buffers[i];
2460 if (buf) {
2461 MEM_freeN(buf);
2462 }
2463 }
2466}
2467
2468static char *wm_clipboard_text_get_impl(bool selection)
2469{
2470 if (UNLIKELY(G.f & G_FLAG_EVENT_SIMULATE)) {
2471 if (g_wm_clipboard_text_simulate == nullptr) {
2472 return nullptr;
2473 }
2474 const char *buf_src = g_wm_clipboard_text_simulate->buffers[int(selection)];
2475 if (buf_src == nullptr) {
2476 return nullptr;
2477 }
2478 size_t size = strlen(buf_src) + 1;
2479 char *buf = static_cast<char *>(malloc(size));
2480 memcpy(buf, buf_src, size);
2481 return buf;
2482 }
2483
2484 return GHOST_getClipboard(selection);
2485}
2486
2487static void wm_clipboard_text_set_impl(const char *buf, bool selection)
2488{
2489 if (UNLIKELY(G.f & G_FLAG_EVENT_SIMULATE)) {
2490 if (g_wm_clipboard_text_simulate == nullptr) {
2492 MEM_callocN<std::remove_pointer_t<decltype(g_wm_clipboard_text_simulate)>>(__func__);
2493 }
2494 char **buf_src_p = &(g_wm_clipboard_text_simulate->buffers[int(selection)]);
2495 MEM_SAFE_FREE(*buf_src_p);
2496 *buf_src_p = BLI_strdup(buf);
2497 return;
2498 }
2499
2500 GHOST_putClipboard(buf, selection);
2501}
2502
2504
2505/* -------------------------------------------------------------------- */
2508
2509static char *wm_clipboard_text_get_ex(bool selection,
2510 int *r_len,
2511 const bool ensure_utf8,
2512 const bool firstline)
2513{
2514 if (G.background) {
2515 *r_len = 0;
2516 return nullptr;
2517 }
2518
2519 char *buf = wm_clipboard_text_get_impl(selection);
2520 if (!buf) {
2521 *r_len = 0;
2522 return nullptr;
2523 }
2524
2525 int buf_len = strlen(buf);
2526
2527 if (ensure_utf8) {
2528 /* TODO(@ideasman42): It would be good if unexpected byte sequences could be interpreted
2529 * instead of stripped - so mixed in characters (typically Latin1) aren't ignored.
2530 * Check on how Python bytes this, see: #PyC_UnicodeFromBytesAndSize,
2531 * there are clever ways to handle this although they increase the size of the buffer. */
2532 buf_len -= BLI_str_utf8_invalid_strip(buf, buf_len);
2533 }
2534
2535 /* Always convert from `\r\n` to `\n`. */
2536 char *newbuf = MEM_malloc_arrayN<char>(size_t(buf_len + 1), __func__);
2537 char *p2 = newbuf;
2538
2539 if (firstline) {
2540 /* Will return an over-allocated value in the case there are newlines. */
2541 for (char *p = buf; *p; p++) {
2542 if (!ELEM(*p, '\n', '\r')) {
2543 *(p2++) = *p;
2544 }
2545 else {
2546 break;
2547 }
2548 }
2549 }
2550 else {
2551 for (char *p = buf; *p; p++) {
2552 if (*p != '\r') {
2553 *(p2++) = *p;
2554 }
2555 }
2556 }
2557
2558 *p2 = '\0';
2559
2560 free(buf); /* GHOST uses regular malloc. */
2561
2562 *r_len = (p2 - newbuf);
2563
2564 return newbuf;
2565}
2566
2567char *WM_clipboard_text_get(bool selection, bool ensure_utf8, int *r_len)
2568{
2569 return wm_clipboard_text_get_ex(selection, r_len, ensure_utf8, false);
2570}
2571
2572char *WM_clipboard_text_get_firstline(bool selection, bool ensure_utf8, int *r_len)
2573{
2574 return wm_clipboard_text_get_ex(selection, r_len, ensure_utf8, true);
2575}
2576
2577void WM_clipboard_text_set(const char *buf, bool selection)
2578{
2579 if (!G.background) {
2580#ifdef _WIN32
2581 /* Do conversion from `\n` to `\r\n` on Windows. */
2582 const char *p;
2583 char *p2, *newbuf;
2584 int newlen = 0;
2585
2586 for (p = buf; *p; p++) {
2587 if (*p == '\n') {
2588 newlen += 2;
2589 }
2590 else {
2591 newlen++;
2592 }
2593 }
2594
2595 newbuf = MEM_calloc_arrayN<char>(newlen + 1, "WM_clipboard_text_set");
2596
2597 for (p = buf, p2 = newbuf; *p; p++, p2++) {
2598 if (*p == '\n') {
2599 *(p2++) = '\r';
2600 *p2 = '\n';
2601 }
2602 else {
2603 *p2 = *p;
2604 }
2605 }
2606 *p2 = '\0';
2607
2608 wm_clipboard_text_set_impl(newbuf, selection);
2609 MEM_freeN(newbuf);
2610#else
2611 wm_clipboard_text_set_impl(buf, selection);
2612#endif
2613 }
2614}
2615
2617{
2618 if (G.background) {
2619 return false;
2620 }
2621 return bool(GHOST_hasClipboardImage());
2622}
2623
2625{
2626 if (G.background) {
2627 return nullptr;
2628 }
2629
2630 int width, height;
2631
2632 uint8_t *rgba = (uint8_t *)GHOST_getClipboardImage(&width, &height);
2633 if (!rgba) {
2634 return nullptr;
2635 }
2636
2637 ImBuf *ibuf = IMB_allocFromBuffer(rgba, nullptr, width, height, 4);
2638 free(rgba);
2639
2640 return ibuf;
2641}
2642
2644{
2645 if (G.background) {
2646 return false;
2647 }
2648 if (ibuf->byte_buffer.data == nullptr) {
2649 return false;
2650 }
2651
2652 bool success = bool(GHOST_putClipboardImage((uint *)ibuf->byte_buffer.data, ibuf->x, ibuf->y));
2653
2654 return success;
2655}
2656
2658
2659/* -------------------------------------------------------------------- */
2662
2664{
2665 /* In background mode we may have windows, but not actual GHOST windows. */
2666 if (win->ghostwin) {
2667 GHOST_SetProgressBar(static_cast<GHOST_WindowHandle>(win->ghostwin), progress);
2668 }
2669}
2670
2672{
2673 if (win->ghostwin) {
2674 GHOST_EndProgressBar(static_cast<GHOST_WindowHandle>(win->ghostwin));
2675 }
2676}
2677
2679
2680/* -------------------------------------------------------------------- */
2683
2684void wm_window_set_size(wmWindow *win, int width, int height)
2685{
2686 GHOST_SetClientSize(static_cast<GHOST_WindowHandle>(win->ghostwin), width, height);
2687}
2688
2690
2691/* -------------------------------------------------------------------- */
2694
2696{
2697 GHOST_SetWindowOrder(static_cast<GHOST_WindowHandle>(win->ghostwin), GHOST_kWindowOrderBottom);
2698}
2699
2701{
2702 /* Restore window if minimized. */
2703 if (GHOST_GetWindowState(static_cast<GHOST_WindowHandle>(win->ghostwin)) ==
2705 {
2706 GHOST_SetWindowState(static_cast<GHOST_WindowHandle>(win->ghostwin), GHOST_kWindowStateNormal);
2707 }
2708 GHOST_SetWindowOrder(static_cast<GHOST_WindowHandle>(win->ghostwin), GHOST_kWindowOrderTop);
2709}
2710
2712
2713/* -------------------------------------------------------------------- */
2716
2718{
2719 GHOST_SwapWindowBuffers(static_cast<GHOST_WindowHandle>(win->ghostwin));
2720}
2721
2723{
2724 GHOST_SetSwapInterval(static_cast<GHOST_WindowHandle>(win->ghostwin), interval);
2725}
2726
2727bool wm_window_get_swap_interval(wmWindow *win, int *r_interval)
2728{
2729 return GHOST_GetSwapInterval(static_cast<GHOST_WindowHandle>(win->ghostwin), r_interval);
2730}
2731
2733
2734/* -------------------------------------------------------------------- */
2737
2739 const int event_xy[2],
2740 int r_event_xy_other[2])
2741{
2743 /* Window positions are unsupported, so this function can't work as intended.
2744 * Perform the bare minimum, return the active window if the event is within it. */
2745 rcti rect;
2746 WM_window_rect_calc(win, &rect);
2747 if (!BLI_rcti_isect_pt_v(&rect, event_xy)) {
2748 return nullptr;
2749 }
2750 copy_v2_v2_int(r_event_xy_other, event_xy);
2751 return win;
2752 }
2753
2754 int temp_xy[2];
2755 copy_v2_v2_int(temp_xy, event_xy);
2756 wm_cursor_position_to_ghost_screen_coords(win, &temp_xy[0], &temp_xy[1]);
2757
2758 GHOST_WindowHandle ghostwin = GHOST_GetWindowUnderCursor(g_system, temp_xy[0], temp_xy[1]);
2759
2760 if (!ghostwin) {
2761 return nullptr;
2762 }
2763
2764 wmWindow *win_other = static_cast<wmWindow *>(GHOST_GetWindowUserData(ghostwin));
2765 wm_cursor_position_from_ghost_screen_coords(win_other, &temp_xy[0], &temp_xy[1]);
2766 copy_v2_v2_int(r_event_xy_other, temp_xy);
2767 return win_other;
2768}
2769
2771{
2772 LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
2774 if (BLI_findindex(&sc->areabase, area) != -1) {
2775 return win;
2776 }
2777 }
2778 return nullptr;
2779}
2780
2782
2783/* -------------------------------------------------------------------- */
2786
2787void WM_init_state_size_set(int stax, int stay, int sizx, int sizy)
2788{
2789 wm_init_state.start = blender::int2(stax, stay); /* Left hand bottom position. */
2790 wm_init_state.size = blender::int2(std::max(sizx, 640), std::max(sizy, 480));
2791 wm_init_state.override_flag |= WIN_OVERRIDE_GEOM;
2792}
2793
2799
2801{
2803 wm_init_state.override_flag |= WIN_OVERRIDE_WINSTATE;
2804}
2805
2811
2813{
2814 wm_init_state.window_focus = do_it;
2815}
2816
2818{
2819 wm_init_state.native_pixels = do_it;
2820}
2821
2823
2824/* -------------------------------------------------------------------- */
2827
2829{
2830 if (UNLIKELY(!g_system)) {
2831 return;
2832 }
2833
2835
2836 switch (U.tablet_api) {
2837 case USER_TABLET_NATIVE:
2839 break;
2840 case USER_TABLET_WINTAB:
2842 break;
2844 default:
2846 break;
2847 }
2848}
2849
2850void WM_cursor_warp(wmWindow *win, int x, int y)
2851{
2852 /* This function requires access to the GHOST_SystemHandle (`g_system`). */
2853
2854 if (!(win && win->ghostwin)) {
2855 return;
2856 }
2857
2858 int oldx = x, oldy = y;
2859
2861 GHOST_SetCursorPosition(g_system, static_cast<GHOST_WindowHandle>(win->ghostwin), x, y);
2862
2863 win->eventstate->prev_xy[0] = oldx;
2864 win->eventstate->prev_xy[1] = oldy;
2865
2866 win->eventstate->xy[0] = oldx;
2867 win->eventstate->xy[1] = oldy;
2868}
2869
2874
2876
2877/* -------------------------------------------------------------------- */
2880
2882{
2883 const float fac = GHOST_GetNativePixelSize(static_cast<GHOST_WindowHandle>(win->ghostwin));
2884
2885 return int(fac * float(win->sizex));
2886}
2888{
2889 const float fac = GHOST_GetNativePixelSize(static_cast<GHOST_WindowHandle>(win->ghostwin));
2890
2891 return int(fac * float(win->sizey));
2892}
2893
2895{
2896 const float fac = GHOST_GetNativePixelSize(static_cast<GHOST_WindowHandle>(win->ghostwin));
2897
2898 return blender::int2(int(fac * float(win->sizex)), int(fac * float(win->sizey)));
2899}
2900
2901void WM_window_native_pixel_coords(const wmWindow *win, int *x, int *y)
2902{
2903 const float fac = GHOST_GetNativePixelSize(static_cast<GHOST_WindowHandle>(win->ghostwin));
2904
2905 *x *= fac;
2906 *y *= fac;
2907}
2908
2909void WM_window_rect_calc(const wmWindow *win, rcti *r_rect)
2910{
2911 const blender::int2 win_size = WM_window_native_pixel_size(win);
2912 BLI_rcti_init(r_rect, 0, win_size[0], 0, win_size[1]);
2913}
2915{
2916 rcti window_rect, screen_rect;
2917
2918 WM_window_rect_calc(win, &window_rect);
2919 screen_rect = window_rect;
2920
2921 /* Subtract global areas from screen rectangle. */
2922 LISTBASE_FOREACH (ScrArea *, global_area, &win->global_areas.areabase) {
2923 int height = ED_area_global_size_y(global_area) - 1;
2924
2925 if (global_area->global->flag & GLOBAL_AREA_IS_HIDDEN) {
2926 continue;
2927 }
2928
2929 switch (global_area->global->align) {
2931 screen_rect.ymax -= height;
2932 break;
2934 screen_rect.ymin += height;
2935 break;
2936 default:
2938 break;
2939 }
2940 }
2941
2942 BLI_assert(BLI_rcti_is_valid(&screen_rect));
2943
2944 *r_rect = screen_rect;
2945}
2946
2948{
2950}
2951
2953{
2955}
2956
2958{
2964 if ((win->parent != nullptr) || screen->temp) {
2965 return false;
2966 }
2967 return true;
2968}
2969
2971
2972/* -------------------------------------------------------------------- */
2975
2976void WM_windows_scene_data_sync(const ListBase *win_lb, Scene *scene)
2977{
2978 LISTBASE_FOREACH (wmWindow *, win, win_lb) {
2979 if (WM_window_get_active_scene(win) == scene) {
2980 ED_workspace_scene_data_sync(win->workspace_hook, scene);
2981 }
2982 }
2983}
2984
2986{
2987 LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
2988 if (WM_window_get_active_screen(win) == screen) {
2989 return WM_window_get_active_scene(win);
2990 }
2991 }
2992
2993 return nullptr;
2994}
2995
2997{
2998 LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
2999 if (WM_window_get_active_screen(win) == screen) {
3001 }
3002 }
3003
3004 return nullptr;
3005}
3006
3008{
3009 LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
3010 if (WM_window_get_active_screen(win) == screen) {
3012 }
3013 }
3014 return nullptr;
3015}
3016
3018{
3019 return win->scene;
3020}
3021
3023{
3025 wmWindow *win_parent = (win->parent) ? win->parent : win;
3026 bool changed = false;
3027
3028 /* Set scene in parent and its child windows. */
3029 if (win_parent->scene != scene) {
3030 ED_screen_scene_change(C, win_parent, scene, true);
3031 changed = true;
3032 }
3033
3034 LISTBASE_FOREACH (wmWindow *, win_child, &wm->windows) {
3035 if (win_child->parent == win_parent && win_child->scene != scene) {
3036 ED_screen_scene_change(C, win_child, scene, true);
3037 changed = true;
3038 }
3039 }
3040
3041 if (changed) {
3042 /* Update depsgraph and renderers for scene change. */
3043 ViewLayer *view_layer = WM_window_get_active_view_layer(win_parent);
3044 ED_scene_change_update(bmain, scene, view_layer);
3045
3046 /* Complete redraw. */
3048 }
3049}
3050
3052{
3053 Scene *scene = WM_window_get_active_scene(win);
3054 if (scene == nullptr) {
3055 return nullptr;
3056 }
3057
3058 ViewLayer *view_layer = BKE_view_layer_find(scene, win->view_layer_name);
3059 if (view_layer) {
3060 return view_layer;
3061 }
3062
3063 view_layer = BKE_view_layer_default_view(scene);
3064 if (view_layer) {
3065 WM_window_set_active_view_layer((wmWindow *)win, view_layer);
3066 }
3067
3068 return view_layer;
3069}
3070
3072{
3073 BLI_assert(BKE_view_layer_find(WM_window_get_active_scene(win), view_layer->name) != nullptr);
3074 Main *bmain = G_MAIN;
3075
3076 wmWindowManager *wm = static_cast<wmWindowManager *>(bmain->wm.first);
3077 wmWindow *win_parent = (win->parent) ? win->parent : win;
3078
3079 /* Set view layer in parent and child windows. */
3080 LISTBASE_FOREACH (wmWindow *, win_iter, &wm->windows) {
3081 if ((win_iter == win_parent) || (win_iter->parent == win_parent)) {
3082 STRNCPY(win_iter->view_layer_name, view_layer->name);
3083 bScreen *screen = BKE_workspace_active_screen_get(win_iter->workspace_hook);
3084 ED_render_view_layer_changed(bmain, screen);
3085 }
3086 }
3087}
3088
3090{
3091 /* Update layer name is correct after scene changes, load without UI, etc. */
3092 Scene *scene = WM_window_get_active_scene(win);
3093
3094 if (scene && BKE_view_layer_find(scene, win->view_layer_name) == nullptr) {
3095 ViewLayer *view_layer = BKE_view_layer_default_view(scene);
3096 STRNCPY(win->view_layer_name, view_layer->name);
3097 }
3098}
3099
3104
3106{
3108 wmWindow *win_parent = (win->parent) ? win->parent : win;
3109
3110 ED_workspace_change(workspace, C, wm, win);
3111
3112 LISTBASE_FOREACH (wmWindow *, win_child, &wm->windows) {
3113 if (win_child->parent == win_parent) {
3114 bScreen *screen = WM_window_get_active_screen(win_child);
3115 /* Don't change temporary screens, they only serve a single purpose. */
3116 if (screen->temp) {
3117 continue;
3118 }
3119 ED_workspace_change(workspace, C, wm, win_child);
3120 }
3121 }
3122}
3123
3125{
3126 const WorkSpace *workspace = WM_window_get_active_workspace(win);
3127 return (LIKELY(workspace != nullptr) ? BKE_workspace_active_layout_get(win->workspace_hook) :
3128 nullptr);
3129}
3131{
3132 BKE_workspace_active_layout_set(win->workspace_hook, win->winid, workspace, layout);
3133}
3134
3136{
3137 const WorkSpace *workspace = WM_window_get_active_workspace(win);
3138 /* May be null in rare cases like closing Blender. */
3139 return (LIKELY(workspace != nullptr) ? BKE_workspace_active_screen_get(win->workspace_hook) :
3140 nullptr);
3141}
3143{
3144 BKE_workspace_active_screen_set(win->workspace_hook, win->winid, workspace, screen);
3145}
3146
3148{
3149 const bScreen *screen = WM_window_get_active_screen(win);
3150 return (screen && screen->temp != 0);
3151}
3152
3154
3155/* -------------------------------------------------------------------- */
3158
3159#ifdef WITH_INPUT_IME
3160void wm_window_IME_begin(wmWindow *win, int x, int y, int w, int h, bool complete)
3161{
3162 /* NOTE: Keep in mind #wm_window_IME_begin is also used to reposition the IME window. */
3163
3164 BLI_assert(win);
3166 return;
3167 }
3168
3169 /* Convert to native OS window coordinates. */
3170 float fac = GHOST_GetNativePixelSize(static_cast<GHOST_WindowHandle>(win->ghostwin));
3171 x /= fac;
3172 y /= fac;
3174 static_cast<GHOST_WindowHandle>(win->ghostwin), x, win->sizey - y, w, h, complete);
3175}
3176
3177void wm_window_IME_end(wmWindow *win)
3178{
3180 return;
3181 }
3182
3183 BLI_assert(win);
3184 /* NOTE(@ideasman42): on WAYLAND a call to "begin" must be closed by an "end" call.
3185 * Even if no IME events were generated (which assigned `ime_data`).
3186 * TODO: check if #GHOST_EndIME can run on WIN32 & APPLE without causing problems. */
3187# if defined(WIN32) || defined(__APPLE__)
3188 BLI_assert(win->runtime->ime_data);
3189# endif
3190 GHOST_EndIME(static_cast<GHOST_WindowHandle>(win->ghostwin));
3191 MEM_delete(win->runtime->ime_data);
3192 win->runtime->ime_data = nullptr;
3193 win->runtime->ime_data_is_composing = false;
3194}
3195#endif /* WITH_INPUT_IME */
3196
3198
3199/* -------------------------------------------------------------------- */
3202
3204{
3205 /* On Windows there is a problem creating contexts that share resources (almost any object,
3206 * including legacy display lists, but also textures) with a context which is current in another
3207 * thread. This is a documented and behavior of both `::wglCreateContextAttribsARB()` and
3208 * `::wglShareLists()`.
3209 *
3210 * Other platforms might successfully share resources from context which is active somewhere
3211 * else, but to keep our code behave the same on all platform we expect contexts to only be
3212 * created from the main thread. */
3213
3216
3217 GHOST_GPUSettings gpuSettings = {0};
3218 const eGPUBackendType gpu_backend = GPU_backend_type_selection_get();
3219 gpuSettings.context_type = wm_ghost_drawing_context_type(gpu_backend);
3220 if (G.debug & G_DEBUG_GPU) {
3221 gpuSettings.flags |= GHOST_gpuDebugContext;
3222 }
3223 gpuSettings.preferred_device.index = U.gpu_preferred_index;
3224 gpuSettings.preferred_device.vendor_id = U.gpu_preferred_vendor_id;
3225 gpuSettings.preferred_device.device_id = U.gpu_preferred_device_id;
3226
3227 return GHOST_CreateGPUContext(g_system, gpuSettings);
3228}
3229
3231{
3233 GHOST_DisposeGPUContext(g_system, (GHOST_ContextHandle)context);
3234}
3235
3237{
3239 GHOST_ActivateGPUContext((GHOST_ContextHandle)context);
3240}
3241
3243{
3245 GHOST_ReleaseGPUContext((GHOST_ContextHandle)context);
3246}
3247
3248void WM_ghost_show_message_box(const char *title,
3249 const char *message,
3250 const char *help_label,
3251 const char *continue_label,
3252 const char *link,
3253 GHOST_DialogOptions dialog_options)
3254{
3256 GHOST_ShowMessageBox(g_system, title, message, help_label, continue_label, link, dialog_options);
3257}
3258
const char * BKE_blender_version_string(void)
Definition blender.cc:143
bScreen * CTX_wm_screen(const bContext *C)
wmWindow * CTX_wm_window(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
void CTX_wm_window_set(bContext *C, wmWindow *win)
Main * CTX_data_main(const bContext *C)
void CTX_wm_area_set(bContext *C, ScrArea *area)
wmWindowManager * CTX_wm_manager(const bContext *C)
ViewLayer * CTX_data_view_layer(const bContext *C)
@ G_FLAG_EVENT_SIMULATE
@ G_FLAG_GPU_BACKEND_FALLBACK_QUIET
@ G_FLAG_GPU_BACKEND_FALLBACK
#define G_MAIN
@ G_DEBUG_GPU
@ G_DEBUG_GHOST
@ G_DEBUG_WINTAB
@ G_DEBUG_EVENTS
void BKE_icon_changed(int icon_id)
Definition icons.cc:204
ViewLayer * BKE_view_layer_default_view(const Scene *scene)
ViewLayer * BKE_view_layer_find(const Scene *scene, const char *layer_name)
const char * BKE_main_blendfile_path_from_global()
Definition main.cc:877
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition report.cc:126
void BKE_screen_area_map_free(ScrAreaMap *area_map) ATTR_NONNULL()
Definition screen.cc:648
ScrArea * BKE_screen_find_big_area(const bScreen *screen, int spacetype, short min)
Definition screen.cc:938
WorkSpaceInstanceHook * BKE_workspace_instance_hook_create(const Main *bmain, int winid)
Definition workspace.cc:337
void BKE_workspace_instance_hook_free(const Main *bmain, WorkSpaceInstanceHook *hook)
Definition workspace.cc:351
bScreen * BKE_workspace_layout_screen_get(const WorkSpaceLayout *layout) GETTER_ATTRS
Definition workspace.cc:637
void BKE_workspace_active_screen_set(WorkSpaceInstanceHook *hook, int winid, WorkSpace *workspace, bScreen *screen) SETTER_ATTRS
Definition workspace.cc:616
void BKE_workspace_layout_remove(Main *bmain, WorkSpace *workspace, WorkSpaceLayout *layout) ATTR_NONNULL()
Definition workspace.cc:397
void BKE_workspace_active_layout_set(WorkSpaceInstanceHook *hook, int winid, WorkSpace *workspace, WorkSpaceLayout *layout) SETTER_ATTRS
Activate a layout.
Definition workspace.cc:603
bScreen * BKE_workspace_active_screen_get(const WorkSpaceInstanceHook *hook) GETTER_ATTRS
Definition workspace.cc:612
WorkSpace * BKE_workspace_active_get(WorkSpaceInstanceHook *hook) GETTER_ATTRS
Definition workspace.cc:561
void BKE_workspace_active_set(WorkSpaceInstanceHook *hook, WorkSpace *workspace) SETTER_ATTRS
Definition workspace.cc:565
WorkSpaceLayout * BKE_workspace_active_layout_get(const WorkSpaceInstanceHook *hook) GETTER_ATTRS
Definition workspace.cc:585
#define BLF_DRAW_STR_DUMMY_MAX
Definition BLF_api.hh:468
void BLF_cache_clear()
Definition blf.cc:98
float BLF_width(int fontid, const char *str, size_t str_len, ResultBLF *r_info=nullptr) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(2)
Definition blf.cc:805
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define BLI_assert(a)
Definition BLI_assert.h:46
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:53
#define OS_WINDOWS
#define OS_MAC
void BLI_kdtree_nd_ free(KDTree *tree)
int BLI_findindex(const ListBase *listbase, const void *vlink) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:586
#define LISTBASE_FOREACH(type, var, list)
BLI_INLINE bool BLI_listbase_is_empty(const ListBase *lb)
#define LISTBASE_FOREACH_MUTABLE(type, var, list)
void BLI_addtail(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:111
void BLI_remlink(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:131
void * BLI_pophead(ListBase *listbase) ATTR_NONNULL(1)
Definition listbase.cc:252
void void BLI_INLINE bool BLI_listbase_is_single(const ListBase *lb)
MINLINE float max_ff(float a, float b)
MINLINE int max_ii(int a, int b)
MINLINE void copy_v2_v2_int(int r[2], const int a[2])
MINLINE void copy_v3_v3(float r[3], const float a[3])
void void void const char * BLI_path_basename(const char *path) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT
#define FILE_MAX
const char * BLI_path_extension_or_end(const char *filepath) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL
bool BLI_rcti_isect_pt_v(const struct rcti *rect, const int xy[2])
BLI_INLINE int BLI_rcti_size_y(const struct rcti *rct)
Definition BLI_rect.h:198
bool BLI_rcti_is_valid(const struct rcti *rect)
void BLI_rcti_init(struct rcti *rect, int xmin, int xmax, int ymin, int ymax)
Definition rct.cc:414
void BLI_rcti_resize_y(struct rcti *rect, int y)
Definition rct.cc:615
BLI_INLINE int BLI_rcti_size_x(const struct rcti *rct)
Definition BLI_rect.h:194
void BLI_rcti_resize_x(struct rcti *rect, int x)
Definition rct.cc:609
char * BLI_strdup(const char *str) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC
Definition string.cc:41
#define SNPRINTF(dst, format,...)
Definition BLI_string.h:599
char * STRNCPY(char(&dst)[N], const char *src)
Definition BLI_string.h:688
const char * BLI_str_utf8_invalid_substitute_as_needed(const char *str, size_t str_len, const char substitute, char *buf, const size_t buf_maxncpy) ATTR_NONNULL(1
int BLI_str_utf8_invalid_strip(char *str, size_t str_len) ATTR_NONNULL(1)
unsigned int uint
void BLI_system_backtrace(FILE *fp)
Definition system.cc:102
int BLI_thread_is_main(void)
Definition threads.cc:179
Platform independent time functions.
void BLI_time_sleep_ms(int ms)
Definition time.cc:85
double BLI_time_now_seconds(void)
Definition time.cc:65
#define CLAMP(a, b, c)
#define ARRAY_SIZE(arr)
#define ENUM_OPERATORS(_type, _max)
#define POINTER_AS_UINT(i)
#define UNLIKELY(x)
#define ELEM(...)
#define POINTER_FROM_UINT(i)
#define LIKELY(x)
#define RPT_(msgid)
#define IFACE_(msgid)
#define CLOG_INFO(clg_ref, level,...)
Definition CLG_log.h:179
These structs are the foundation for all linked lists in the library system.
@ S3D_DISPLAY_PAGEFLIP
@ GLOBAL_AREA_IS_HIDDEN
@ RGN_TYPE_WINDOW
@ RGN_TYPE_HEADER
@ GLOBAL_AREA_ALIGN_BOTTOM
@ GLOBAL_AREA_ALIGN_TOP
@ SPACE_TOPBAR
@ SPACE_EMPTY
#define SPACE_TYPE_ANY
#define UI_SCALE_FAC
@ USER_SAVE_PROMPT
@ USER_NO_MULTITOUCH_GESTURES
@ USER_TABLET_NATIVE
@ USER_TABLET_AUTOMATIC
@ USER_TABLET_WINTAB
@ VIRTUAL_PIXEL_NATIVE
@ VIRTUAL_PIXEL_DOUBLE
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
@ WM_INIT_FLAG_WINDOW
int ED_file_extension_icon(const char *path)
Definition filelist.cc:2842
void ED_render_view_layer_changed(Main *bmain, bScreen *screen)
void ED_scene_change_update(Main *bmain, Scene *scene, ViewLayer *layer) ATTR_NONNULL()
void ED_area_newspace(bContext *C, ScrArea *area, int type, bool skip_region_exit)
Definition area.cc:2693
WorkSpaceLayout * ED_workspace_layout_add(Main *bmain, WorkSpace *workspace, wmWindow *win, const char *name) ATTR_NONNULL()
int ED_area_global_size_y(const ScrArea *area)
Definition area.cc:3781
void ED_screen_scene_change(bContext *C, wmWindow *win, Scene *scene, bool refresh_toolsystem)
void ED_screen_refresh(bContext *C, wmWindowManager *wm, wmWindow *win)
void ED_screen_global_areas_refresh(wmWindow *win)
bool ED_screen_change(bContext *C, bScreen *screen)
Change the active screen.
void ED_screen_exit(bContext *C, wmWindow *window, bScreen *screen)
blender::StringRefNull ED_area_name(const ScrArea *area)
void ED_workspace_scene_data_sync(WorkSpaceInstanceHook *hook, Scene *scene) ATTR_NONNULL()
WorkSpaceLayout * ED_workspace_layout_duplicate(Main *bmain, WorkSpace *workspace, const WorkSpaceLayout *layout_old, wmWindow *win) ATTR_NONNULL()
bool ED_workspace_change(WorkSpace *workspace_new, bContext *C, wmWindowManager *wm, wmWindow *win) ATTR_NONNULL()
Change the active workspace.
GHOST C-API function and type declarations.
GHOST_TWindowState GHOST_GetWindowState(GHOST_WindowHandle windowhandle)
GHOST_TSuccess GHOST_putClipboardImage(uint *rgba, int width, int height)
void GHOST_SetWindowDecorationStyleSettings(GHOST_WindowHandle windowhandle, GHOST_WindowDecorationStyleSettings decorationSettings)
GHOST_TSuccess GHOST_GetCursorPosition(const GHOST_SystemHandle systemhandle, const GHOST_WindowHandle windowhandle, int32_t *x, int32_t *y)
GHOST_ContextHandle GHOST_CreateGPUContext(GHOST_SystemHandle systemhandle, GHOST_GPUSettings gpuSettings)
GHOST_TSuccess GHOST_SetWindowOrder(GHOST_WindowHandle windowhandle, GHOST_TWindowOrder order)
GHOST_TUserDataPtr GHOST_GetWindowUserData(GHOST_WindowHandle windowhandle)
GHOST_TSuccess GHOST_SetClientSize(GHOST_WindowHandle windowhandle, uint32_t width, uint32_t height)
GHOST_TSuccess GHOST_hasClipboardImage(void)
void GHOST_SetWindowDecorationStyleFlags(GHOST_WindowHandle windowhandle, GHOST_TWindowDecorationStyleFlags styleFlags)
GHOST_TSuccess GHOST_SetCursorPosition(GHOST_SystemHandle systemhandle, GHOST_WindowHandle windowhandle, int32_t x, int32_t y)
void GHOST_ShowMessageBox(GHOST_SystemHandle systemhandle, const char *title, const char *message, const char *help_label, const char *continue_label, const char *link, GHOST_DialogOptions dialog_options)
void GHOST_ClientToScreen(GHOST_WindowHandle windowhandle, int32_t inX, int32_t inY, int32_t *outX, int32_t *outY)
GHOST_TCapabilityFlag GHOST_GetCapabilities(void)
GHOST_WindowHandle GHOST_GetWindowUnderCursor(GHOST_SystemHandle systemhandle, int32_t x, int32_t y)
GHOST_EventConsumerHandle GHOST_CreateEventConsumer(GHOST_EventCallbackProcPtr eventCallback, GHOST_TUserDataPtr user_data)
GHOST_SystemHandle GHOST_CreateSystem(void)
GHOST_TSuccess GHOST_AddEventConsumer(GHOST_SystemHandle systemhandle, GHOST_EventConsumerHandle consumerhandle)
GHOST_SystemHandle GHOST_CreateSystemBackground(void)
GHOST_TSuccess GHOST_GetAllDisplayDimensions(GHOST_SystemHandle systemhandle, uint32_t *r_width, uint32_t *r_height)
uint16_t GHOST_GetDPIHint(GHOST_WindowHandle windowhandle)
uint32_t GHOST_GetCursorPreferredLogicalSize(const GHOST_SystemHandle systemhandle)
void GHOST_DisposeRectangle(GHOST_RectangleHandle rectanglehandle)
GHOST_TSuccess GHOST_SetPath(GHOST_WindowHandle windowhandle, const char *filepath)
void GHOST_UseWindowFocus(bool use_focus)
bool GHOST_ProcessEvents(GHOST_SystemHandle systemhandle, bool waitForEvent)
void GHOST_SetTitle(GHOST_WindowHandle windowhandle, const char *title)
void GHOST_BeginIME(GHOST_WindowHandle windowhandle, int32_t x, int32_t y, int32_t w, int32_t h, bool complete)
GHOST_TSuccess GHOST_ReleaseGPUContext(GHOST_ContextHandle contexthandle)
void GHOST_ScreenToClient(GHOST_WindowHandle windowhandle, int32_t inX, int32_t inY, int32_t *outX, int32_t *outY)
char * GHOST_getClipboard(bool selection)
uint64_t GHOST_GetEventTime(GHOST_EventHandle eventhandle)
GHOST_TSuccess GHOST_SetProgressBar(GHOST_WindowHandle windowhandle, float progress)
GHOST_TSuccess GHOST_SetWindowModifiedState(GHOST_WindowHandle windowhandle, bool isUnsavedChanges)
GHOST_TSuccess GHOST_DisposeWindow(GHOST_SystemHandle systemhandle, GHOST_WindowHandle windowhandle)
GHOST_TSuccess GHOST_ActivateGPUContext(GHOST_ContextHandle contexthandle)
GHOST_TSuccess GHOST_SetWindowState(GHOST_WindowHandle windowhandle, GHOST_TWindowState state)
void GHOST_SetBacktraceHandler(GHOST_TBacktraceFn backtrace_fn)
void GHOST_SetTabletAPI(GHOST_SystemHandle systemhandle, GHOST_TTabletAPI api)
GHOST_TSuccess GHOST_SwapWindowBuffers(GHOST_WindowHandle windowhandle)
void GHOST_SetMultitouchGestures(GHOST_SystemHandle systemhandle, const bool use)
GHOST_TEventDataPtr GHOST_GetEventData(GHOST_EventHandle eventhandle)
uint * GHOST_getClipboardImage(int *r_width, int *r_height)
GHOST_TSuccess GHOST_ActivateWindowDrawingContext(GHOST_WindowHandle windowhandle)
GHOST_TSuccess GHOST_GetModifierKeyState(GHOST_SystemHandle systemhandle, GHOST_TModifierKey mask, bool *r_is_down)
GHOST_WindowHandle GHOST_CreateWindow(GHOST_SystemHandle systemhandle, GHOST_WindowHandle parent_windowhandle, const char *title, int32_t left, int32_t top, uint32_t width, uint32_t height, GHOST_TWindowState state, bool is_dialog, GHOST_GPUSettings gpuSettings)
bool GHOST_ValidWindow(GHOST_SystemHandle systemhandle, GHOST_WindowHandle windowhandle)
float GHOST_GetNativePixelSize(GHOST_WindowHandle windowhandle)
GHOST_TEventType GHOST_GetEventType(GHOST_EventHandle eventhandle)
bool GHOST_IsDialogWindow(GHOST_WindowHandle windowhandle)
void GHOST_SystemInitDebug(GHOST_SystemHandle systemhandle, GHOST_Debug debug)
GHOST_TSuccess GHOST_ApplyWindowDecorationStyle(GHOST_WindowHandle windowhandle)
void GHOST_putClipboard(const char *buffer, bool selection)
void GHOST_SetWindowUserData(GHOST_WindowHandle windowhandle, GHOST_TUserDataPtr user_data)
const char * GHOST_SystemBackend(void)
GHOST_WindowHandle GHOST_GetEventWindow(GHOST_EventHandle eventhandle)
void GHOST_GetRectangle(GHOST_RectangleHandle rectanglehandle, int32_t *l, int32_t *t, int32_t *r, int32_t *b)
GHOST_TWindowDecorationStyleFlags GHOST_GetWindowDecorationStyleFlags(GHOST_WindowHandle windowhandle)
void GHOST_EndIME(GHOST_WindowHandle windowhandle)
bool GHOST_UseNativePixels(void)
void GHOST_DispatchEvents(GHOST_SystemHandle systemhandle)
GHOST_TSuccess GHOST_DisposeGPUContext(GHOST_SystemHandle systemhandle, GHOST_ContextHandle contexthandle)
GHOST_TSuccess GHOST_EndProgressBar(GHOST_WindowHandle windowhandle)
GHOST_TSuccess GHOST_SetSwapInterval(GHOST_WindowHandle windowhandle, int interval)
GHOST_RectangleHandle GHOST_GetClientBounds(GHOST_WindowHandle windowhandle)
GHOST_TSuccess GHOST_DisposeSystem(GHOST_SystemHandle systemhandle)
uint64_t GHOST_GetMilliSeconds(GHOST_SystemHandle systemhandle)
GHOST_TSuccess GHOST_GetSwapInterval(GHOST_WindowHandle windowhandle, int *r_interval)
GHOST_TSuccess GHOST_GetMainDisplayDimensions(GHOST_SystemHandle systemhandle, uint32_t *r_width, uint32_t *r_height)
GHOST_TWindowState
@ GHOST_kWindowStateMinimized
@ GHOST_kWindowStateMaximized
@ GHOST_kWindowStateNormal
@ GHOST_kWindowStateFullScreen
void * GHOST_TUserDataPtr
Definition GHOST_Types.h:78
GHOST_TEventType
@ GHOST_kEventWindowClose
@ GHOST_kEventWindowMove
@ GHOST_kEventWindowSize
@ GHOST_kEventDraggingDropDone
@ GHOST_kEventNativeResolutionChange
@ GHOST_kEventOpenMainFile
@ GHOST_kEventButtonUp
@ GHOST_kEventWindowActivate
@ GHOST_kEventWindowUpdateDecor
@ GHOST_kEventWindowUpdate
@ GHOST_kEventWindowDeactivate
@ GHOST_kEventButtonDown
@ GHOST_kEventKeyDown
@ GHOST_kEventWindowDPIHintChanged
@ GHOST_kEventKeyUp
@ GHOST_kEventQuitRequest
@ GHOST_kDebugDefault
@ GHOST_kDebugWintab
GHOST_TCapabilityFlag
Definition GHOST_Types.h:89
@ GHOST_kCapabilityWindowPosition
Definition GHOST_Types.h:97
@ GHOST_kCapabilityKeyboardHyperKey
@ GHOST_kCapabilityGPUReadFrontBuffer
@ GHOST_kCapabilityCursorWarp
Definition GHOST_Types.h:93
@ GHOST_kCapabilityInputIME
@ GHOST_kCapabilityTrackpadPhysicalDirection
@ GHOST_kCapabilityClipboardImages
@ GHOST_kCapabilityPrimaryClipboard
@ GHOST_kCapabilityWindowDecorationStyles
@ GHOST_kCapabilityDesktopSample
GHOST_TKey
@ GHOST_kKeyLeftOS
@ GHOST_kKeyLeftAlt
@ GHOST_kKeyRightShift
@ GHOST_kKeyRightOS
@ GHOST_kKeyLeftControl
@ GHOST_kKeyLeftHyper
@ GHOST_kKeyRightAlt
@ GHOST_kKeyRightControl
@ GHOST_kKeyUnknown
@ GHOST_kKeyRightHyper
@ GHOST_kKeyLeftShift
const void * GHOST_TEventDataPtr
GHOST_TDrawingContextType
@ GHOST_kDrawingContextTypeNone
@ GHOST_kWindowOrderTop
@ GHOST_kWindowOrderBottom
GHOST_TModifierKey
@ GHOST_kModifierKeyRightControl
@ GHOST_kModifierKeyLeftControl
@ GHOST_kModifierKeyRightHyper
@ GHOST_kModifierKeyRightAlt
@ GHOST_kModifierKeyRightShift
@ GHOST_kModifierKeyLeftAlt
@ GHOST_kModifierKeyLeftShift
@ GHOST_kModifierKeyLeftOS
@ GHOST_kModifierKeyRightOS
@ GHOST_kModifierKeyLeftHyper
@ GHOST_kFailure
Definition GHOST_Types.h:80
@ GHOST_kSuccess
Definition GHOST_Types.h:80
@ GHOST_gpuStereoVisual
Definition GHOST_Types.h:69
@ GHOST_gpuDebugContext
Definition GHOST_Types.h:70
void(* GHOST_TBacktraceFn)(void *file_handle)
Definition GHOST_Types.h:56
@ GHOST_kDragnDropTypeFilenames
@ GHOST_kDragnDropTypeString
@ GHOST_kTabletAutomatic
@ GHOST_kTabletWinPointer
@ GHOST_kTabletWintab
GHOST_DialogOptions
Definition GHOST_Types.h:73
GHOST_TWindowDecorationStyleFlags
@ GHOST_kDecorationNone
@ GHOST_kDecorationColoredTitleBar
void GPU_render_end()
GPUContext * GPU_context_create(void *ghost_window, void *ghost_context)
void GPU_render_begin()
eGPUBackendType GPU_backend_type_selection_get()
void GPU_context_discard(GPUContext *)
void GPU_context_active_set(GPUContext *)
void GPU_backend_ghost_system_set(void *ghost_system_handle)
GPUFrameBuffer * GPU_framebuffer_active_get()
void GPU_clear_color(float red, float green, float blue, float alpha)
GPUFrameBuffer * GPU_framebuffer_back_get()
void GPU_init()
ImBuf * IMB_allocFromBuffer(const uint8_t *byte_buffer, const float *float_buffer, unsigned int w, unsigned int h, unsigned int channels)
Read Guarded memory(de)allocation.
#define C
Definition RandGen.cpp:29
@ UI_BLOCK_THEME_STYLE_POPUP
void UI_block_emboss_set(uiBlock *block, blender::ui::EmbossType emboss)
void UI_block_theme_style_set(uiBlock *block, char theme_style)
uiBlock * UI_block_begin(const bContext *C, ARegion *region, std::string name, blender::ui::EmbossType emboss)
void UI_popup_block_invoke(bContext *C, uiBlockCreateFunc func, void *arg, uiFreeArgFunc arg_free)
const uiStyle * UI_style_get_dpi()
void UI_fontstyle_set(const uiFontStyle *fs)
void UI_block_bounds_set_centered(uiBlock *block, int addval)
Definition interface.cc:667
void UI_popup_handlers_remove_all(bContext *C, ListBase *handlers)
@ ALERT_ICON_ERROR
uiLayout * uiItemsAlertBox(uiBlock *block, const uiStyle *style, const int dialog_width, const eAlertIcon icon, const int icon_size)
void uiLayoutSetScaleY(uiLayout *layout, float scale)
uiBut * uiItemL_ex(uiLayout *layout, blender::StringRef name, int icon, bool highlight, bool redalert)
void UI_GetThemeColor3fv(int colorid, float col[3])
@ TH_BACK
@ TH_BUTBACK_TEXT
void UI_SetTheme(int spacetype, int regionid)
eWindowAlignment
Definition WM_api.hh:360
@ WIN_ALIGN_LOCATION_CENTER
Definition WM_api.hh:362
@ WIN_ALIGN_PARENT_CENTER
Definition WM_api.hh:363
eWM_CapabilitiesFlag
Definition WM_api.hh:166
@ WM_CAPABILITY_PRIMARY_CLIPBOARD
Definition WM_api.hh:187
@ WM_CAPABILITY_WINDOW_POSITION
Definition WM_api.hh:182
@ WM_CAPABILITY_CURSOR_WARP
Definition WM_api.hh:168
@ WM_CAPABILITY_INITIALIZED
Definition WM_api.hh:205
@ WM_CAPABILITY_TRACKPAD_PHYSICAL_DIRECTION
Definition WM_api.hh:199
@ WM_CAPABILITY_WINDOW_DECORATION_STYLES
Definition WM_api.hh:201
@ WM_CAPABILITY_GPU_FRONT_BUFFER_READ
Definition WM_api.hh:191
@ WM_CAPABILITY_KEYBOARD_HYPER_KEY
Definition WM_api.hh:203
@ WM_CAPABILITY_CLIPBOARD_IMAGES
Definition WM_api.hh:193
@ WM_CAPABILITY_DESKTOP_SAMPLE
Definition WM_api.hh:195
@ WM_CAPABILITY_INPUT_IME
Definition WM_api.hh:197
eWM_WindowDecorationStyleFlag
Definition WM_api.hh:407
@ WM_WINDOW_DECORATION_STYLE_COLORED_TITLEBAR
Definition WM_api.hh:411
@ WM_WINDOW_DECORATION_STYLE_NONE
Definition WM_api.hh:409
#define NC_WINDOW
Definition WM_types.hh:372
@ KM_CTRL
Definition WM_types.hh:276
@ KM_ALT
Definition WM_types.hh:277
@ KM_HYPER
Definition WM_types.hh:289
@ KM_OSKEY
Definition WM_types.hh:279
@ KM_SHIFT
Definition WM_types.hh:275
eWM_EventFlag
Definition WM_types.hh:668
@ WM_DRAG_NOP
Definition WM_types.hh:1225
@ WM_DRAG_FREE_DATA
Definition WM_types.hh:1226
CLG_LogRef * WM_LOG_EVENTS
#define NC_SCREEN
Definition WM_types.hh:374
#define NA_ADDED
Definition WM_types.hh:583
#define NA_EDITED
Definition WM_types.hh:581
#define NA_REMOVED
Definition WM_types.hh:584
@ WM_OP_INVOKE_DEFAULT
Definition WM_types.hh:238
@ WM_DRAG_PATH
Definition WM_types.hh:1205
@ WM_DRAG_STRING
Definition WM_types.hh:1214
float progress
Definition WM_types.hh:1019
@ WM_TIMER_TAGGED_FOR_REMOVAL
Definition WM_types.hh:945
@ WM_TIMER_NO_FREE_CUSTOM_DATA
Definition WM_types.hh:940
#define ND_LAYOUTDELETE
Definition WM_types.hh:420
@ KM_NOTHING
Definition WM_types.hh:307
@ KM_RELEASE
Definition WM_types.hh:309
#define U
BMesh const char void * data
ATTR_WARN_UNUSED_RESULT const BMLoop * l
void activate(bool forceActivation=false) const
unsigned long long int uint64_t
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition btQuadWord.h:119
#define str(s)
uint col
#define ceil
#define printf(...)
#define MEM_SAFE_FREE(v)
#define PRIu64
Definition inttypes.h:132
void * MEM_calloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:123
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void * MEM_malloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:133
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
static ulong state[N]
#define G(x, y, z)
VecBase< int32_t, 2 > int2
void RNA_string_set(PointerRNA *ptr, const char *name, const char *value)
void RNA_boolean_set(PointerRNA *ptr, const char *name, bool value)
GHOST_TDrawingContextType context_type
GHOST_GPUDevice preferred_device
GHOST_TDragnDropTypes dataType
GHOST_TDragnDropDataPtr data
int icon_id
Definition DNA_ID.h:426
ImBufByteBuffer byte_buffer
void * first
ListBase wm
Definition BKE_main.hh:276
ListBase areabase
char name[64]
GHOST_TWindowState windowstate
Definition wm_window.cc:127
blender::int2 size
Definition wm_window.cc:124
blender::int2 start
Definition wm_window.cc:125
eWinOverrideFlag override_flag
Definition wm_window.cc:128
bool window_focus
Definition wm_window.cc:130
bool native_pixels
Definition wm_window.cc:131
Wrapper for bScreen.
ListBase areabase
int ymin
int ymax
int xmin
int xmax
void label(blender::StringRef name, int icon)
uiLayout & column(bool align)
uiFontStyle widget
short columnspace
wmEventModifierFlag modifier
Definition WM_types.hh:771
int xy[2]
Definition WM_types.hh:758
int prev_xy[2]
Definition WM_types.hh:817
wmEventType keymodifier
Definition WM_types.hh:780
wmGenericCallbackFn exec
Definition WM_types.hh:150
struct ReportList * reports
wmTimerFlags flags
Definition WM_types.hh:960
double time_next
Definition WM_types.hh:972
void * customdata
Definition WM_types.hh:962
wmWindow * win
Definition WM_types.hh:953
double time_start
Definition WM_types.hh:974
double time_step
Definition WM_types.hh:956
double time_last
Definition WM_types.hh:970
wmEventType event_type
Definition WM_types.hh:958
struct wmKeyConfig * defaultconf
WindowManagerRuntimeHandle * runtime
struct wmWindow * winactive
struct wmWindow * windrawable
struct wmWindow * parent
WindowRuntimeHandle * runtime
struct wmEvent * eventstate
struct wmEvent * event_last_handled
struct Scene * scene
struct wmEvent_ConsecutiveData * event_queue_consecutive_gesture_data
struct wmWindow * next
ScrAreaMap global_areas
struct WorkSpaceInstanceHook * workspace_hook
struct Stereo3dFormat * stereo3d_format
i
Definition text_draw.cc:230
wmTimer * timer
void WM_check(bContext *C)
Definition wm.cc:471
@ WM_CURSOR_DEFAULT
Definition wm_cursors.hh:15
wmDragPath * WM_drag_create_path_data(blender::Span< const char * > paths)
void WM_event_start_drag(bContext *C, int icon, eWM_DragDataType type, void *poin, uint flags)
ListBase * WM_dropboxmap_find(const char *idname, int spaceid, int regionid)
int xy[2]
Definition wm_draw.cc:174
int winid
Definition wm_draw.cc:173
void wm_draw_update(bContext *C)
Definition wm_draw.cc:1581
wmEventHandler_Dropbox * WM_event_add_dropbox_handler(ListBase *handlers, ListBase *dropboxes)
wmEventHandler_Keymap * WM_event_add_keymap_handler(ListBase *handlers, wmKeyMap *keymap)
void wm_event_do_handlers(bContext *C)
void WM_event_add_notifier_ex(wmWindowManager *wm, const wmWindow *win, uint type, void *reference)
void WM_event_consecutive_data_free(wmWindow *win)
void WM_main_add_notifier(uint type, void *reference)
void wm_event_free_all(wmWindow *win)
wmOperatorStatus WM_operator_name_call_ptr(bContext *C, wmOperatorType *ot, wmOperatorCallContext context, PointerRNA *properties, const wmEvent *event)
wmEvent * WM_event_add(wmWindow *win, const wmEvent *event_to_add)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
void wm_event_do_notifiers(bContext *C)
void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, const int type, const void *customdata, const uint64_t event_time_ms)
void wm_event_init_from_window(wmWindow *win, wmEvent *event)
void WM_event_remove_handlers(bContext *C, ListBase *handlers)
@ EVT_DATA_DRAGDROP
@ EVT_DATA_TIMER
wmEventType
@ TIMERNOTIFIER
@ TIMERJOBS
@ TIMERAUTOSAVE
@ EVENT_NONE
@ MOUSEMOVE
@ EVT_DROP
#define ISTIMER(event_type)
bool wm_file_or_session_data_has_unsaved_changes(const Main *bmain, const wmWindowManager *wm)
Definition wm_files.cc:184
void wm_autosave_timer(Main *bmain, wmWindowManager *wm, wmTimer *)
Definition wm_files.cc:2387
wmOperatorType * ot
Definition wm_files.cc:4225
void wm_close_file_dialog(bContext *C, wmGenericCallback *post_action)
Definition wm_files.cc:4853
void WM_gestures_free_all(wmWindow *win)
void wm_exit_schedule_delayed(const bContext *C)
void wm_jobs_timer_end(wmWindowManager *wm, wmTimer *wt)
Definition wm_jobs.cc:649
void wm_jobs_timer(wmWindowManager *wm, wmTimer *wt)
Definition wm_jobs.cc:657
wmKeyMap * WM_keymap_ensure(wmKeyConfig *keyconf, const char *idname, int spaceid, int regionid)
Definition wm_keymap.cc:893
wmOperatorType * WM_operatortype_find(const char *idname, bool quiet)
void WM_operator_properties_create_ptr(PointerRNA *ptr, wmOperatorType *ot)
void WM_operator_properties_free(PointerRNA *ptr)
static bool ghost_event_proc(GHOST_EventHandle ghost_event, GHOST_TUserDataPtr ps_void_ptr)
static void ghost_event_proc_timestamp_warning(GHOST_EventHandle ghost_event)
ViewLayer * WM_windows_view_layer_get_from_screen(const wmWindowManager *wm, const bScreen *screen)
blender::int2 WM_window_native_pixel_size(const wmWindow *win)
eWinOverrideFlag
Definition wm_window.cc:101
@ WIN_OVERRIDE_WINSTATE
Definition wm_window.cc:103
@ WIN_OVERRIDE_GEOM
Definition wm_window.cc:102
wmWindow * wm_window_copy(Main *bmain, wmWindowManager *wm, wmWindow *win_src, const bool duplicate_layout, const bool child)
Definition wm_window.cc:329
static void wm_window_ghostwindow_ensure(wmWindowManager *wm, wmWindow *win, bool is_dialog)
Definition wm_window.cc:921
ModSide
Definition wm_window.cc:160
@ MOD_SIDE_RIGHT
Definition wm_window.cc:162
@ MOD_SIDE_LEFT
Definition wm_window.cc:161
void WM_window_set_active_scene(Main *bmain, bContext *C, wmWindow *win, Scene *scene)
wmOperatorStatus wm_window_new_exec(bContext *C, wmOperator *op)
eWM_WindowDecorationStyleFlag WM_window_decoration_style_flags_get(const wmWindow *win)
Definition wm_window.cc:627
void wm_cursor_position_from_ghost_screen_coords(wmWindow *win, int *x, int *y)
GHOST_TKey ghost_key_pair[2]
Definition wm_window.cc:140
static GHOST_SystemHandle g_system
Definition wm_window.cc:96
wmWindow * wm_window_new(const Main *bmain, wmWindowManager *wm, wmWindow *parent, bool dialog)
Definition wm_window.cc:313
static void wm_clipboard_text_set_impl(const char *buf, bool selection)
void WM_clipboard_text_set(const char *buf, bool selection)
void wm_window_raise(wmWindow *win)
void WM_window_ensure_active_view_layer(wmWindow *win)
static char * wm_clipboard_text_get_impl(bool selection)
static void wm_window_check_size(rcti *rect)
Definition wm_window.cc:198
void wm_window_swap_buffers(wmWindow *win)
Push rendered buffer to the screen.
ImBuf * WM_clipboard_image_get()
Scene * WM_windows_scene_get_from_screen(const wmWindowManager *wm, const bScreen *screen)
void WM_init_input_devices()
#define GHOST_WINDOW_STATE_DEFAULT
Definition wm_window.cc:107
void WM_init_state_maximized_set()
void WM_window_set_active_workspace(bContext *C, wmWindow *win, WorkSpace *workspace)
bool WM_window_is_main_top_level(const wmWindow *win)
void wm_cursor_position_to_ghost_client_coords(wmWindow *win, int *x, int *y)
char * WM_clipboard_text_get(bool selection, bool ensure_utf8, int *r_len)
void wm_cursor_position_from_ghost_client_coords(wmWindow *win, int *x, int *y)
void wm_test_gpu_backend_fallback(bContext *C)
void wm_cursor_position_to_ghost_screen_coords(wmWindow *win, int *x, int *y)
void wm_ghost_exit()
char * WM_clipboard_text_get_firstline(bool selection, bool ensure_utf8, int *r_len)
static char * wm_clipboard_text_get_ex(bool selection, int *r_len, const bool ensure_utf8, const bool firstline)
char * buffers[2]
GHOST_TModifierKey ghost_mask_pair[2]
Definition wm_window.cc:141
static struct WMInitStruct wm_init_state
static void wm_window_ensure_eventstate(wmWindow *win)
Definition wm_window.cc:805
void wm_quit_with_optional_confirmation_prompt(bContext *C, wmWindow *win)
Definition wm_window.cc:401
void * WM_system_gpu_context_create()
static uint8_t wm_ghost_modifier_query(const enum ModSide side)
void WM_cursor_warp(wmWindow *win, int x, int y)
void wm_window_reset_drawable()
void WM_event_timers_free_all(wmWindowManager *wm)
static bool ghost_event_proc(GHOST_EventHandle ghost_event, GHOST_TUserDataPtr C_void_ptr)
bool wm_get_screensize(int r_size[2])
Definition wm_window.cc:175
static void wm_window_ghostwindow_add(wmWindowManager *wm, const char *title, wmWindow *win, bool is_dialog)
Definition wm_window.cc:818
void wm_window_events_process(const bContext *C)
static const struct @112313331237150317127363163151143364300335345041 g_modifier_table[]
WorkSpaceLayout * WM_window_get_active_layout(const wmWindow *win)
void WM_system_gpu_context_dispose(void *context)
void WM_event_timer_free_data(wmTimer *timer)
void WM_event_timer_sleep(wmWindowManager *wm, wmWindow *, wmTimer *timer, bool do_sleep)
void WM_window_native_pixel_coords(const wmWindow *win, int *x, int *y)
void wm_test_opengl_deprecation_warning(bContext *C)
static void wm_ghostwindow_destroy(wmWindowManager *wm, wmWindow *win)
Definition wm_window.cc:211
bool wm_cursor_position_get(wmWindow *win, int *r_x, int *r_y)
bool WM_window_is_fullscreen(const wmWindow *win)
void wm_window_close(bContext *C, wmWindowManager *wm, wmWindow *win)
Definition wm_window.cc:433
void wm_window_set_swap_interval(wmWindow *win, int interval)
static void wm_window_update_eventstate_modifiers(wmWindowManager *wm, wmWindow *win, const uint64_t event_time_ms)
Definition wm_window.cc:704
void WM_window_set_active_screen(wmWindow *win, WorkSpace *workspace, bScreen *screen)
static bool wm_window_timers_process(const bContext *C, int *sleep_us_p)
static void wm_confirm_quit(bContext *C)
Definition wm_window.cc:394
wmOperatorStatus wm_window_close_exec(bContext *C, wmOperator *)
void WM_init_native_pixels(bool do_it)
void wm_window_set_size(wmWindow *win, int width, int height)
void WM_window_set_dpi(const wmWindow *win)
Definition wm_window.cc:575
void wm_ghost_init_background()
WorkSpace * WM_windows_workspace_get_from_screen(const wmWindowManager *wm, const bScreen *screen)
int WM_window_native_pixel_y(const wmWindow *win)
int WM_window_native_pixel_x(const wmWindow *win)
bool wm_window_get_swap_interval(wmWindow *win, int *r_interval)
void wm_clipboard_free()
wmTimer * WM_event_timer_add_notifier(wmWindowManager *wm, wmWindow *win, const uint type, const double time_step)
void wm_window_ghostwindows_remove_invalid(bContext *C, wmWindowManager *wm)
wmWindow * WM_window_open(bContext *C, const char *title, const rcti *rect_unscaled, int space_type, bool toplevel, bool dialog, bool temp, eWindowAlignment alignment, void(*area_setup_fn)(bScreen *screen, ScrArea *area, void *user_data), void *area_setup_user_data)
void WM_system_gpu_context_activate(void *context)
void WM_event_timer_remove_notifier(wmWindowManager *wm, wmWindow *win, wmTimer *timer)
struct @101311165077003061362006267100311210331331056372 * g_wm_clipboard_text_simulate
void wm_window_clear_drawable(wmWindowManager *wm)
static uiBlock * block_create_gpu_backend_fallback(bContext *C, ARegion *region, void *)
wmOperatorStatus wm_window_new_main_exec(bContext *C, wmOperator *op)
wmTimer * WM_event_timer_add(wmWindowManager *wm, wmWindow *win, const wmEventType event_type, const double time_step)
static int find_free_winid(wmWindowManager *wm)
Definition wm_window.cc:301
void WM_progress_clear(wmWindow *win)
void WM_init_state_size_set(int stax, int stay, int sizx, int sizy)
static void wm_window_decoration_style_set_from_theme(const wmWindow *win, const bScreen *screen)
Definition wm_window.cc:656
void WM_progress_set(wmWindow *win, float progress)
void wm_window_make_drawable(wmWindowManager *wm, wmWindow *win)
wmWindow * wm_window_copy_test(bContext *C, wmWindow *win_src, const bool duplicate_layout, const bool child)
Definition wm_window.cc:359
static bool wm_window_update_size_position(wmWindow *win)
bool WM_clipboard_image_available()
static uiBlock * block_create_opengl_usage_warning(bContext *C, ARegion *region, void *)
const char * WM_ghost_backend()
bool WM_window_is_temp_screen(const wmWindow *win)
wmWindow * WM_window_find_under_cursor(wmWindow *win, const int event_xy[2], int r_event_xy_other[2])
void WM_window_rect_calc(const wmWindow *win, rcti *r_rect)
eWM_CapabilitiesFlag WM_capabilities_flag()
bool WM_window_is_maximized(const wmWindow *win)
uint WM_cursor_preferred_logical_size()
void WM_window_set_active_layout(wmWindow *win, WorkSpace *workspace, WorkSpaceLayout *layout)
wmWindow * WM_window_find_by_area(wmWindowManager *wm, const ScrArea *area)
void WM_window_screen_rect_calc(const wmWindow *win, rcti *r_rect)
void WM_window_set_active_view_layer(wmWindow *win, ViewLayer *view_layer)
ViewLayer * WM_window_get_active_view_layer(const wmWindow *win)
void WM_init_state_fullscreen_set()
static void wm_window_update_eventstate(wmWindow *win)
Definition wm_window.cc:796
void WM_init_state_normal_set()
Scene * WM_window_get_active_scene(const wmWindow *win)
static void wm_save_file_on_quit_dialog_callback(bContext *C, void *)
Definition wm_window.cc:385
static const char * g_system_backend_id
Definition wm_window.cc:98
static void wm_window_update_eventstate_modifiers_clear(wmWindowManager *wm, wmWindow *win, const uint64_t event_time_ms)
Definition wm_window.cc:759
static void wm_window_set_drawable(wmWindowManager *wm, wmWindow *win, bool activate)
void wm_window_free(bContext *C, wmWindowManager *wm, wmWindow *win)
Definition wm_window.cc:239
void WM_event_timer_remove(wmWindowManager *wm, wmWindow *, wmTimer *timer)
void WM_window_title(wmWindowManager *wm, wmWindow *win, const char *title)
Definition wm_window.cc:489
void wm_ghost_init(bContext *C)
GHOST_TDrawingContextType wm_ghost_drawing_context_type(const eGPUBackendType gpu_backend)
bool WM_clipboard_image_set_byte_buffer(ImBuf *ibuf)
void WM_windows_scene_data_sync(const ListBase *win_lb, Scene *scene)
void wm_window_ghostwindows_ensure(wmWindowManager *wm)
Definition wm_window.cc:989
void WM_init_window_focus_set(bool do_it)
void WM_window_decoration_style_flags_set(const wmWindow *win, eWM_WindowDecorationStyleFlag style_flags)
Definition wm_window.cc:641
WorkSpace * WM_window_get_active_workspace(const wmWindow *win)
bool wm_get_desktopsize(int r_size[2])
Definition wm_window.cc:186
void wm_window_timers_delete_removed(wmWindowManager *wm)
wmOperatorStatus wm_window_fullscreen_toggle_exec(bContext *C, wmOperator *)
void wm_window_lower(wmWindow *win)
void WM_ghost_show_message_box(const char *title, const char *message, const char *help_label, const char *continue_label, const char *link, GHOST_DialogOptions dialog_options)
void WM_system_gpu_context_release(void *context)
bScreen * WM_window_get_active_screen(const wmWindow *win)
uint8_t flag
Definition wm_window.cc:139
void WM_window_decoration_style_apply(const wmWindow *win, const bScreen *screen)
Definition wm_window.cc:687
bool wm_xr_events_handle(wmWindowManager *wm)
Definition wm_xr.cc:142