Blender V4.3
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
11#include <chrono>
12#include <cmath>
13#include <cstdio>
14#include <cstdlib>
15#include <cstring>
16#include <thread>
17
18#include "CLG_log.h"
19
20#include "DNA_listBase.h"
21#include "DNA_screen_types.h"
23#include "DNA_workspace_types.h"
24
25#include "MEM_guardedalloc.h"
26
27#include "GHOST_C-api.h"
28
29#include "BLI_blenlib.h"
30#include "BLI_system.h"
31#include "BLI_time.h"
32#include "BLI_utildefines.h"
33
34#include "BLT_translation.hh"
35
36#include "BKE_blender_version.h"
37#include "BKE_context.hh"
38#include "BKE_global.hh"
39#include "BKE_icons.h"
40#include "BKE_layer.hh"
41#include "BKE_main.hh"
42#include "BKE_report.hh"
43#include "BKE_screen.hh"
44#include "BKE_workspace.hh"
45
46#include "RNA_access.hh"
47#include "RNA_define.hh"
48#include "RNA_enum_types.hh"
49#include "RNA_prototypes.hh"
50
51#include "WM_api.hh"
52#include "WM_types.hh"
53#include "wm.hh"
54#include "wm_draw.hh"
55#include "wm_event_system.hh"
56#include "wm_files.hh"
58#include "wm_window.hh"
59#include "wm_window_private.hh"
60#ifdef WITH_XR_OPENXR
61# include "wm_xr.hh"
62#endif
63
64#include "ED_anim_api.hh"
65#include "ED_fileselect.hh"
66#include "ED_render.hh"
67#include "ED_scene.hh"
68#include "ED_screen.hh"
69
70#include "IMB_imbuf.hh"
71#include "IMB_imbuf_types.hh"
72
73#include "UI_interface.hh"
74#include "UI_interface_icons.hh"
75
76#include "BLF_api.hh"
77#include "GPU_batch.hh"
78#include "GPU_batch_presets.hh"
79#include "GPU_context.hh"
80#include "GPU_framebuffer.hh"
81#include "GPU_immediate.hh"
82#include "GPU_init_exit.hh"
83#include "GPU_platform.hh"
84#include "GPU_state.hh"
85#include "GPU_texture.hh"
86
87#include "UI_resources.hh"
88
89/* For assert. */
90#ifndef NDEBUG
91# include "BLI_threads.h"
92#endif
93
94/* The global to talk to GHOST. */
95static GHOST_SystemHandle g_system = nullptr;
96#if !(defined(WIN32) || defined(__APPLE__))
97static const char *g_system_backend_id = nullptr;
98#endif
99
105
106#define GHOST_WINDOW_STATE_DEFAULT GHOST_kWindowStateMaximized
107
132
133/* -------------------------------------------------------------------- */
137static const struct {
141} g_modifier_table[] = {
142 {KM_SHIFT,
145 {KM_CTRL,
148 {KM_ALT,
151 {KM_OSKEY,
155
160
163/* -------------------------------------------------------------------- */
167static void wm_window_set_drawable(wmWindowManager *wm, wmWindow *win, bool activate);
168static bool wm_window_timers_process(const bContext *C, int *sleep_us_p);
169static uint8_t wm_ghost_modifier_query(const enum ModSide side);
170
171bool wm_get_screensize(int r_size[2])
172{
173 uint32_t uiwidth, uiheight;
174 if (GHOST_GetMainDisplayDimensions(g_system, &uiwidth, &uiheight) == GHOST_kFailure) {
175 return false;
176 }
177 r_size[0] = uiwidth;
178 r_size[1] = uiheight;
179 return true;
180}
181
182bool wm_get_desktopsize(int r_size[2])
183{
184 uint32_t uiwidth, uiheight;
185 if (GHOST_GetAllDisplayDimensions(g_system, &uiwidth, &uiheight) == GHOST_kFailure) {
186 return false;
187 }
188 r_size[0] = uiwidth;
189 r_size[1] = uiheight;
190 return true;
191}
192
194static void wm_window_check_size(rcti *rect)
195{
196 blender::int2 scr_size;
197 if (wm_get_screensize(scr_size)) {
198 if (BLI_rcti_size_x(rect) > scr_size[0]) {
199 BLI_rcti_resize_x(rect, scr_size[0]);
200 }
201 if (BLI_rcti_size_y(rect) > scr_size[1]) {
202 BLI_rcti_resize_y(rect, scr_size[1]);
203 }
204 }
205}
206
208{
209 if (UNLIKELY(!win->ghostwin)) {
210 return;
211 }
212
213 /* Prevents non-drawable state of main windows (bugs #22967,
214 * #25071 and possibly #22477 too). Always clear it even if
215 * this window was not the drawable one, because we mess with
216 * drawing context to discard the GW context. */
218
219 if (win == wm->winactive) {
220 wm->winactive = nullptr;
221 }
222
223 /* We need this window's GPU context active to discard it. */
224 GHOST_ActivateWindowDrawingContext(static_cast<GHOST_WindowHandle>(win->ghostwin));
225 GPU_context_active_set(static_cast<GPUContext *>(win->gpuctx));
226
227 /* Delete local GPU context. */
228 GPU_context_discard(static_cast<GPUContext *>(win->gpuctx));
229
230 GHOST_DisposeWindow(g_system, static_cast<GHOST_WindowHandle>(win->ghostwin));
231 win->ghostwin = nullptr;
232 win->gpuctx = nullptr;
233}
234
236{
237 /* Update context. */
238 if (C) {
241
242 if (CTX_wm_window(C) == win) {
243 CTX_wm_window_set(C, nullptr);
244 }
245 }
246
248
249 /* End running jobs, a job end also removes its timer. */
251 if (wt->flags & WM_TIMER_TAGGED_FOR_REMOVAL) {
252 continue;
253 }
254 if (wt->win == win && wt->event_type == TIMERJOBS) {
255 wm_jobs_timer_end(wm, wt);
256 }
257 }
258
259 /* Timer removing, need to call this api function. */
261 if (wt->flags & WM_TIMER_TAGGED_FOR_REMOVAL) {
262 continue;
263 }
264 if (wt->win == win) {
265 WM_event_timer_remove(wm, win, wt);
266 }
267 }
269
270 if (win->eventstate) {
271 MEM_freeN(win->eventstate);
272 }
273 if (win->event_last_handled) {
275 }
278 }
279
280 if (win->cursor_keymap_status) {
282 }
283
285
287
288 wm_ghostwindow_destroy(wm, win);
289
292
293 MEM_freeN(win);
294}
295
297{
298 int id = 1;
299
300 LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
301 if (id <= win->winid) {
302 id = win->winid + 1;
303 }
304 }
305 return id;
306}
307
308wmWindow *wm_window_new(const Main *bmain, wmWindowManager *wm, wmWindow *parent, bool dialog)
309{
310 wmWindow *win = static_cast<wmWindow *>(MEM_callocN(sizeof(wmWindow), "window"));
311
312 BLI_addtail(&wm->windows, win);
313 win->winid = find_free_winid(wm);
314
315 /* Dialogs may have a child window as parent. Otherwise, a child must not be a parent too. */
316 win->parent = (!dialog && parent && parent->parent) ? parent->parent : parent;
317 win->stereo3d_format = static_cast<Stereo3dFormat *>(
318 MEM_callocN(sizeof(Stereo3dFormat), "Stereo 3D Format (window)"));
320
321 return win;
322}
323
325 wmWindowManager *wm,
326 wmWindow *win_src,
327 const bool duplicate_layout,
328 const bool child)
329{
330 const bool is_dialog = GHOST_IsDialogWindow(static_cast<GHOST_WindowHandle>(win_src->ghostwin));
331 wmWindow *win_parent = (child) ? win_src : win_src->parent;
332 wmWindow *win_dst = wm_window_new(bmain, wm, win_parent, is_dialog);
333 WorkSpace *workspace = WM_window_get_active_workspace(win_src);
334 WorkSpaceLayout *layout_old = WM_window_get_active_layout(win_src);
335
336 win_dst->posx = win_src->posx + 10;
337 win_dst->posy = win_src->posy;
338 win_dst->sizex = win_src->sizex;
339 win_dst->sizey = win_src->sizey;
340
341 win_dst->scene = win_src->scene;
342 STRNCPY(win_dst->view_layer_name, win_src->view_layer_name);
343 BKE_workspace_active_set(win_dst->workspace_hook, workspace);
344 WorkSpaceLayout *layout_new = duplicate_layout ? ED_workspace_layout_duplicate(
345 bmain, workspace, layout_old, win_dst) :
346 layout_old;
347 BKE_workspace_active_layout_set(win_dst->workspace_hook, win_dst->winid, workspace, layout_new);
348
349 *win_dst->stereo3d_format = *win_src->stereo3d_format;
350
351 return win_dst;
352}
353
355 wmWindow *win_src,
356 const bool duplicate_layout,
357 const bool child)
358{
359 Main *bmain = CTX_data_main(C);
361
362 wmWindow *win_dst = wm_window_copy(bmain, wm, win_src, duplicate_layout, child);
363
364 WM_check(C);
365
366 if (win_dst->ghostwin) {
368 return win_dst;
369 }
370 wm_window_close(C, wm, win_dst);
371 return nullptr;
372}
373
376/* -------------------------------------------------------------------- */
380static void wm_save_file_on_quit_dialog_callback(bContext *C, void * /*user_data*/)
381{
383}
384
390{
391 wmGenericCallback *action = static_cast<wmGenericCallback *>(
392 MEM_callocN(sizeof(*action), __func__));
394 wm_close_file_dialog(C, action);
395}
396
398{
399 wmWindow *win_ctx = CTX_wm_window(C);
400
401 /* The popup will be displayed in the context window which may not be set
402 * here (this function gets called outside of normal event handling loop). */
403 CTX_wm_window_set(C, win);
404
405 if (U.uiflag & USER_SAVE_PROMPT) {
407 !G.background)
408 {
409 wm_window_raise(win);
411 }
412 else {
414 }
415 }
416 else {
418 }
419
420 CTX_wm_window_set(C, win_ctx);
421}
422
425/* -------------------------------------------------------------------- */
430{
431 wmWindow *win_other;
432
433 /* First check if there is another main window remaining. */
434 for (win_other = static_cast<wmWindow *>(wm->windows.first); win_other;
435 win_other = win_other->next)
436 {
437 if (win_other != win && win_other->parent == nullptr && !WM_window_is_temp_screen(win_other)) {
438 break;
439 }
440 }
441
442 if (win->parent == nullptr && win_other == nullptr) {
444 return;
445 }
446
447 /* Close child windows. */
448 LISTBASE_FOREACH_MUTABLE (wmWindow *, iter_win, &wm->windows) {
449 if (iter_win->parent == win) {
450 wm_window_close(C, wm, iter_win);
451 }
452 }
453
457
458 BLI_remlink(&wm->windows, win);
459
460 CTX_wm_window_set(C, win); /* Needed by handlers. */
462
464
465 /* For regular use this will _never_ be nullptr,
466 * however we may be freeing an improperly initialized window. */
467 if (screen) {
468 ED_screen_exit(C, win, screen);
469 }
470
471 wm_window_free(C, wm, win);
472
473 /* If temp screen, delete it after window free (it stops jobs that can access it). */
474 if (screen && screen->temp) {
475 Main *bmain = CTX_data_main(C);
476
478 BKE_workspace_layout_remove(bmain, workspace, layout);
480 }
481
483}
484
485void WM_window_title(wmWindowManager *wm, wmWindow *win, const char *title)
486{
487 if (win->ghostwin == nullptr) {
488 return;
489 }
490
491 GHOST_WindowHandle handle = static_cast<GHOST_WindowHandle>(win->ghostwin);
492
493 if (title) {
494 GHOST_SetTitle(handle, title);
495 return;
496 }
497
498 if (win->parent || WM_window_is_temp_screen(win)) {
499 /* Not a main window. */
501 const bool is_single = screen && BLI_listbase_is_single(&screen->areabase);
502 ScrArea *area = (screen) ? static_cast<ScrArea *>(screen->areabase.first) : nullptr;
503 const char *name = "Blender";
504 if (is_single && area && area->spacetype != SPACE_EMPTY) {
505 name = IFACE_(ED_area_name(area).c_str());
506 }
507 GHOST_SetTitle(handle, name);
508 return;
509 }
510
511 const char *filepath = BKE_main_blendfile_path_from_global();
512 const char *filename = BLI_path_basename(filepath);
513
514 const bool has_filepath = filepath[0] != '\0';
515 const bool include_filepath = has_filepath && (filepath != filename) &&
516 (GHOST_SetPath(handle, filepath) == GHOST_kFailure);
517
518 std::string str;
519 if (!wm->file_saved) {
520 str += "* ";
521 }
522
523 if (has_filepath) {
524 const size_t filename_no_ext_len = BLI_path_extension_or_end(filename) - filename;
525 str.append(filename, filename_no_ext_len);
526 }
527 else {
528 str += IFACE_("(Unsaved)");
529 }
530
531 if (G_MAIN->recovered) {
532 str += IFACE_(" (Recovered)");
533 }
534
535 if (include_filepath) {
536 str += " [";
537 str += filepath;
538 str += "]";
539 }
540
541 str += " - Blender ";
543
544 GHOST_SetTitle(handle, str.c_str());
545
546 /* Informs GHOST of unsaved changes to set the window modified visual indicator (macOS)
547 * and to give a hint of unsaved changes for a user warning mechanism in case of OS application
548 * terminate request (e.g., OS Shortcut Alt+F4, Command+Q, (...) or session end). */
549 GHOST_SetWindowModifiedState(handle, bool(!wm->file_saved));
550}
551
553{
554 float auto_dpi = GHOST_GetDPIHint(static_cast<GHOST_WindowHandle>(win->ghostwin));
555
556 /* Clamp auto DPI to 96, since our font/interface drawing does not work well
557 * with lower sizes. The main case we are interested in supporting is higher
558 * DPI. If a smaller UI is desired it is still possible to adjust UI scale. */
559 auto_dpi = max_ff(auto_dpi, 96.0f);
560
561 /* Lazily init UI scale size, preserving backwards compatibility by
562 * computing UI scale from ratio of previous DPI and auto DPI. */
563 if (U.ui_scale == 0) {
564 int virtual_pixel = (U.virtual_pixel == VIRTUAL_PIXEL_NATIVE) ? 1 : 2;
565
566 if (U.dpi == 0) {
567 U.ui_scale = virtual_pixel;
568 }
569 else {
570 U.ui_scale = (virtual_pixel * U.dpi * 96.0f) / (auto_dpi * 72.0f);
571 }
572
573 CLAMP(U.ui_scale, 0.25f, 4.0f);
574 }
575
576 /* Blender's UI drawing assumes DPI 72 as a good default following macOS
577 * while Windows and Linux use DPI 96. GHOST assumes a default 96 so we
578 * remap the DPI to Blender's convention. */
579 auto_dpi *= GHOST_GetNativePixelSize(static_cast<GHOST_WindowHandle>(win->ghostwin));
580 U.dpi = auto_dpi * U.ui_scale * (72.0 / 96.0f);
581
582 /* Automatically set larger pixel size for high DPI. */
583 int pixelsize = max_ii(1, int(U.dpi / 64));
584 /* User adjustment for pixel size. */
585 pixelsize = max_ii(1, pixelsize + U.ui_line_width);
586
587 /* Set user preferences globals for drawing, and for forward compatibility. */
588 U.pixelsize = pixelsize;
589 U.virtual_pixel = (pixelsize == 1) ? VIRTUAL_PIXEL_NATIVE : VIRTUAL_PIXEL_DOUBLE;
590 U.scale_factor = U.dpi / 72.0f;
591 U.inv_scale_factor = 1.0f / U.scale_factor;
592
593 /* Widget unit is 20 pixels at 1X scale. This consists of 18 user-scaled units plus
594 * left and right borders of line-width (pixel-size). */
595 U.widget_unit = int(roundf(18.0f * U.scale_factor)) + (2 * pixelsize);
596}
597
609 wmWindow *win,
610 const uint64_t event_time_ms)
611{
612 const uint8_t keymodifier_sided[2] = {
615 };
616 const uint8_t keymodifier = keymodifier_sided[0] | keymodifier_sided[1];
617 const uint8_t keymodifier_eventstate = win->eventstate->modifier;
618 if (keymodifier != keymodifier_eventstate) {
619 GHOST_TEventKeyData kdata{};
620 kdata.key = GHOST_kKeyUnknown;
621 kdata.utf8_buf[0] = '\0';
622 kdata.is_repeat = false;
623 for (int i = 0; i < ARRAY_SIZE(g_modifier_table); i++) {
624 if (keymodifier_eventstate & g_modifier_table[i].flag) {
625 if ((keymodifier & g_modifier_table[i].flag) == 0) {
626 for (int side = 0; side < 2; side++) {
627 if ((keymodifier_sided[side] & g_modifier_table[i].flag) == 0) {
628 kdata.key = g_modifier_table[i].ghost_key_pair[side];
629 wm_event_add_ghostevent(wm, win, GHOST_kEventKeyUp, &kdata, event_time_ms);
630 /* Only ever send one release event
631 * (currently releasing multiple isn't needed and only confuses logic). */
632 break;
633 }
634 }
635 }
636 }
637 else {
638 if (keymodifier & g_modifier_table[i].flag) {
639 for (int side = 0; side < 2; side++) {
640 if (keymodifier_sided[side] & g_modifier_table[i].flag) {
641 kdata.key = g_modifier_table[i].ghost_key_pair[side];
642 wm_event_add_ghostevent(wm, win, GHOST_kEventKeyDown, &kdata, event_time_ms);
643 }
644 }
645 }
646 }
647 }
648 }
649}
650
664 wmWindow *win,
665 const uint64_t event_time_ms)
666{
667 /* Release all held modifiers before de-activating the window. */
668 if (win->eventstate->modifier != 0) {
669 const uint8_t keymodifier_eventstate = win->eventstate->modifier;
670 const uint8_t keymodifier_l = wm_ghost_modifier_query(MOD_SIDE_LEFT);
671 const uint8_t keymodifier_r = wm_ghost_modifier_query(MOD_SIDE_RIGHT);
672 /* NOTE(@ideasman42): when non-zero, there are modifiers held in
673 * `win->eventstate` which are not considered held by the GHOST internal state.
674 * While this should not happen, it's important all modifier held in event-state
675 * receive release events. Without this, so any events generated while the window
676 * is *not* active will have modifiers held. */
677 const uint8_t keymodifier_unhandled = keymodifier_eventstate &
678 ~(keymodifier_l | keymodifier_r);
679 const uint8_t keymodifier_sided[2] = {
680 uint8_t(keymodifier_l | keymodifier_unhandled),
681 keymodifier_r,
682 };
683 GHOST_TEventKeyData kdata{};
684 kdata.key = GHOST_kKeyUnknown;
685 kdata.utf8_buf[0] = '\0';
686 kdata.is_repeat = false;
687 for (int i = 0; i < ARRAY_SIZE(g_modifier_table); i++) {
688 if (keymodifier_eventstate & g_modifier_table[i].flag) {
689 for (int side = 0; side < 2; side++) {
690 if ((keymodifier_sided[side] & g_modifier_table[i].flag) == 0) {
691 kdata.key = g_modifier_table[i].ghost_key_pair[side];
692 wm_event_add_ghostevent(wm, win, GHOST_kEventKeyUp, &kdata, event_time_ms);
693 }
694 }
695 }
696 }
697 }
698}
699
701{
702 /* Update mouse position when a window is activated. */
703 int xy[2];
704 if (wm_cursor_position_get(win, &xy[0], &xy[1])) {
706 }
707}
708
710{
711 if (win->eventstate) {
712 return;
713 }
714
715 win->eventstate = static_cast<wmEvent *>(MEM_callocN(sizeof(wmEvent), "window event state"));
717}
718
720
721/* Belongs to below. */
723 const char *title,
724 wmWindow *win,
725 bool is_dialog)
726{
727 /* A new window is created when page-flip mode is required for a window. */
728 GHOST_GPUSettings gpuSettings = {0};
730 gpuSettings.flags |= GHOST_gpuStereoVisual;
731 }
732
733 if (G.debug & G_DEBUG_GPU) {
734 gpuSettings.flags |= GHOST_gpuDebugContext;
735 }
736
738 gpuSettings.context_type = wm_ghost_drawing_context_type(gpu_backend);
739 gpuSettings.preferred_device.index = U.gpu_preferred_index;
740 gpuSettings.preferred_device.vendor_id = U.gpu_preferred_vendor_id;
741 gpuSettings.preferred_device.device_id = U.gpu_preferred_device_id;
742
743 int posx = 0;
744 int posy = 0;
745
747 blender::int2 scr_size;
748 if (wm_get_desktopsize(scr_size)) {
749 posx = win->posx;
750 posy = (scr_size[1] - win->posy - win->sizey);
751 }
752 }
753
754 /* Clear drawable so we can set the new window. */
755 wmWindow *prev_windrawable = wm->windrawable;
757
758 GHOST_WindowHandle ghostwin = GHOST_CreateWindow(
759 g_system,
760 static_cast<GHOST_WindowHandle>((win->parent) ? win->parent->ghostwin : nullptr),
761 title,
762 posx,
763 posy,
764 win->sizex,
765 win->sizey,
767 is_dialog,
768 gpuSettings);
769
770 if (ghostwin) {
771 win->gpuctx = GPU_context_create(ghostwin, nullptr);
773
774 /* Needed so we can detect the graphics card below. */
775 GPU_init();
776
777 /* Set window as drawable upon creation. Note this has already been
778 * it has already been activated by GHOST_CreateWindow. */
779 wm_window_set_drawable(wm, win, false);
780
781 win->ghostwin = ghostwin;
782 GHOST_SetWindowUserData(ghostwin, win); /* Pointer back. */
783
785
786 /* Store actual window size in blender window. */
787 /* WIN32: gives undefined window size when minimized. */
788 if (GHOST_GetWindowState(static_cast<GHOST_WindowHandle>(win->ghostwin)) !=
790 {
792 }
793
794#ifndef __APPLE__
795 /* Set the state here, so minimized state comes up correct on windows. */
798 }
799#endif
800 /* Until screens get drawn, make it nice gray. */
801 GPU_clear_color(0.25f, 0.25f, 0.25f, 1.0f);
802
803 /* Needed here, because it's used before it reads userdef. */
805
807
808 /* Clear double buffer to avoids flickering of new windows on certain drivers, see #97600. */
809 GPU_clear_color(0.25f, 0.25f, 0.25f, 1.0f);
810
812 }
813 else {
814 wm_window_set_drawable(wm, prev_windrawable, false);
815 }
816}
817
818static void wm_window_ghostwindow_ensure(wmWindowManager *wm, wmWindow *win, bool is_dialog)
819{
820 if (win->ghostwin == nullptr) {
821 if ((win->sizex == 0) || (wm_init_state.override_flag & WIN_OVERRIDE_GEOM)) {
822 win->posx = wm_init_state.start[0];
823 win->posy = wm_init_state.start[1];
824 win->sizex = wm_init_state.size[0];
825 win->sizey = wm_init_state.size[1];
826
829 wm_init_state.override_flag &= ~WIN_OVERRIDE_GEOM;
830 }
831 else {
833 }
834 }
835
838 wm_init_state.override_flag &= ~WIN_OVERRIDE_WINSTATE;
839 }
840
841 /* Without this, cursor restore may fail, see: #45456. */
842 if (win->cursor == 0) {
844 }
845
846 wm_window_ghostwindow_add(wm, "Blender", win, is_dialog);
847 }
848
849 if (win->ghostwin != nullptr) {
850 /* If we have no `ghostwin` this is a buggy window that should be removed.
851 * However we still need to initialize it correctly so the screen doesn't hang. */
852
853 /* Happens after file-read. */
855
857 }
858
859 /* Add key-map handlers (1 handler for all keys in map!). */
862
865
866 keymap = WM_keymap_ensure(wm->defaultconf, "Screen Editing", SPACE_EMPTY, RGN_TYPE_WINDOW);
868
869 /* Add drop boxes. */
870 {
873 }
874 WM_window_title(wm, win);
875
876 /* Add top-bar. */
878}
879
881{
882 BLI_assert(G.background == false);
883
884 /* No command-line prefsize? then we set this.
885 * Note that these values will be used only
886 * when there is no startup.blend yet.
887 */
888 if (wm_init_state.size[0] == 0) {
890 /* Use fallback values. */
892 }
893
894 /* NOTE: this isn't quite correct, active screen maybe offset 1000s if PX,
895 * we'd need a #wm_get_screensize like function that gives offset,
896 * in practice the window manager will likely move to the correct monitor. */
898 }
899
900 LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
901 wm_window_ghostwindow_ensure(wm, win, false);
902 }
903}
904
906{
907 BLI_assert(G.background == false);
908
910 if (win->ghostwin == nullptr) {
911 wm_window_close(C, wm, win);
912 }
913 }
914}
915
916/* Update window size and position based on data from GHOST window. */
918{
919 GHOST_RectangleHandle client_rect = GHOST_GetClientBounds(
920 static_cast<GHOST_WindowHandle>(win->ghostwin));
921 int l, t, r, b;
922 GHOST_GetRectangle(client_rect, &l, &t, &r, &b);
923
924 GHOST_DisposeRectangle(client_rect);
925
926 int sizex = r - l;
927 int sizey = b - t;
928
929 int posx = 0;
930 int posy = 0;
931
933 blender::int2 scr_size;
934 if (wm_get_desktopsize(scr_size)) {
935 posx = l;
936 posy = scr_size[1] - t - win->sizey;
937 }
938 }
939
940 if (win->sizex != sizex || win->sizey != sizey || win->posx != posx || win->posy != posy) {
941 win->sizex = sizex;
942 win->sizey = sizey;
943 win->posx = posx;
944 win->posy = posy;
945 return true;
946 }
947 return false;
948}
949
951 const char *title,
952 const rcti *rect_unscaled,
953 int space_type,
954 bool toplevel,
955 bool dialog,
956 bool temp,
957 eWindowAlignment alignment,
958 void (*area_setup_fn)(bScreen *screen, ScrArea *area, void *user_data),
959 void *area_setup_user_data)
960{
961 Main *bmain = CTX_data_main(C);
963 wmWindow *win_prev = CTX_wm_window(C);
964 Scene *scene = CTX_data_scene(C);
965 ViewLayer *view_layer = CTX_data_view_layer(C);
966 int x = rect_unscaled->xmin;
967 int y = rect_unscaled->ymin;
968 int sizex = BLI_rcti_size_x(rect_unscaled);
969 int sizey = BLI_rcti_size_y(rect_unscaled);
970 rcti rect;
971
972 const float native_pixel_size = GHOST_GetNativePixelSize(
973 static_cast<GHOST_WindowHandle>(win_prev->ghostwin));
974 /* Convert to native OS window coordinates. */
975 rect.xmin = win_prev->posx + (x / native_pixel_size);
976 rect.ymin = win_prev->posy + (y / native_pixel_size);
977 sizex /= native_pixel_size;
978 sizey /= native_pixel_size;
979
980 if (alignment == WIN_ALIGN_LOCATION_CENTER) {
981 /* Window centered around x,y location. */
982 rect.xmin -= sizex / 2;
983 rect.ymin -= sizey / 2;
984 }
985 else if (alignment == WIN_ALIGN_PARENT_CENTER) {
986 /* Centered within parent. X,Y as offsets from there. */
987 rect.xmin += (win_prev->sizex - sizex) / 2;
988 rect.ymin += (win_prev->sizey - sizey) / 2;
989 }
990 else {
991 /* Positioned absolutely within parent bounds. */
992 }
993
994 rect.xmax = rect.xmin + sizex;
995 rect.ymax = rect.ymin + sizey;
996
997 /* Changes rect to fit within desktop. */
999
1000 /* Reuse temporary windows when they share the same single area. */
1001 wmWindow *win = nullptr;
1002 if (temp) {
1003 LISTBASE_FOREACH (wmWindow *, win_iter, &wm->windows) {
1004 const bScreen *screen = WM_window_get_active_screen(win_iter);
1005 if (screen && screen->temp && BLI_listbase_is_single(&screen->areabase)) {
1006 ScrArea *area = static_cast<ScrArea *>(screen->areabase.first);
1007 if (space_type == (area->butspacetype ? area->butspacetype : area->spacetype)) {
1008 win = win_iter;
1009 break;
1010 }
1011 }
1012 }
1013 }
1014
1015 /* Add new window? */
1016 if (win == nullptr) {
1017 win = wm_window_new(bmain, wm, toplevel ? nullptr : win_prev, dialog);
1018 win->posx = rect.xmin;
1019 win->posy = rect.ymin;
1020 win->sizex = BLI_rcti_size_x(&rect);
1021 win->sizey = BLI_rcti_size_y(&rect);
1022 *win->stereo3d_format = *win_prev->stereo3d_format;
1023 }
1024
1025 bScreen *screen = WM_window_get_active_screen(win);
1026
1027 if (WM_window_get_active_workspace(win) == nullptr) {
1028 WorkSpace *workspace = WM_window_get_active_workspace(win_prev);
1030 }
1031
1032 if (screen == nullptr) {
1033 /* Add new screen layout. */
1034 WorkSpace *workspace = WM_window_get_active_workspace(win);
1035 WorkSpaceLayout *layout = ED_workspace_layout_add(bmain, workspace, win, "temp");
1036
1037 screen = BKE_workspace_layout_screen_get(layout);
1038 WM_window_set_active_layout(win, workspace, layout);
1039 }
1040
1041 /* Set scene and view layer to match original window. */
1042 STRNCPY(win->view_layer_name, view_layer->name);
1043 if (WM_window_get_active_scene(win) != scene) {
1044 /* No need to refresh the tool-system as the window has not yet finished being setup. */
1045 ED_screen_scene_change(C, win, scene, false);
1046 }
1047
1048 screen->temp = temp;
1049
1050 /* Make window active, and validate/resize. */
1051 CTX_wm_window_set(C, win);
1052 const bool new_window = (win->ghostwin == nullptr);
1053 if (new_window) {
1054 wm_window_ghostwindow_ensure(wm, win, dialog);
1055 }
1056 WM_check(C);
1057
1058 /* It's possible `win->ghostwin == nullptr`.
1059 * instead of attempting to cleanup here (in a half finished state),
1060 * finish setting up the screen, then free it at the end of the function,
1061 * to avoid having to take into account a partially-created window.
1062 */
1063
1064 if (area_setup_fn) {
1065 /* When the caller is setting up the area, it should always be empty
1066 * because it's expected the callback sets the type. */
1067 BLI_assert(space_type == SPACE_EMPTY);
1068 /* NOTE(@ideasman42): passing in a callback to setup the `area` is admittedly awkward.
1069 * This is done so #ED_screen_refresh has a valid area to initialize,
1070 * otherwise it will attempt to make the empty area usable via #ED_area_init.
1071 * While refreshing the window could be postponed this makes the state of the
1072 * window less predictable to the caller. */
1073 ScrArea *area = static_cast<ScrArea *>(screen->areabase.first);
1074 area_setup_fn(screen, area, area_setup_user_data);
1075 CTX_wm_area_set(C, area);
1076 }
1077 else if (space_type != SPACE_EMPTY) {
1078 /* Ensure it shows the right space-type editor. */
1079 ScrArea *area = static_cast<ScrArea *>(screen->areabase.first);
1080 CTX_wm_area_set(C, area);
1081 ED_area_newspace(C, area, space_type, false);
1082 }
1083
1084 ED_screen_change(C, screen);
1085
1086 if (!new_window) {
1087 /* Set size in GHOST window and then update size and position from GHOST,
1088 * in case they where changed by GHOST to fit the monitor/screen. */
1089 wm_window_set_size(win, win->sizex, win->sizey);
1091 }
1092
1093 /* Refresh screen dimensions, after the effective window size is known. */
1094 ED_screen_refresh(C, wm, win);
1095
1096 if (win->ghostwin) {
1097 wm_window_raise(win);
1098 WM_window_title(wm, win, title);
1099 return win;
1100 }
1101
1102 /* Very unlikely! but opening a new window can fail. */
1103 wm_window_close(C, wm, win);
1104 CTX_wm_window_set(C, win_prev);
1105
1106 return nullptr;
1107}
1108
1111/* -------------------------------------------------------------------- */
1116{
1118 wmWindow *win = CTX_wm_window(C);
1119 wm_window_close(C, wm, win);
1120 return OPERATOR_FINISHED;
1121}
1122
1124{
1125 wmWindow *win_src = CTX_wm_window(C);
1127 const rcti window_rect = {
1128 /*xmin*/ 0,
1129 /*xmax*/ int(win_src->sizex * 0.95f),
1130 /*ymin*/ 0,
1131 /*ymax*/ int(win_src->sizey * 0.9f),
1132 };
1133
1134 bool ok = (WM_window_open(C,
1135 nullptr,
1136 &window_rect,
1137 area->spacetype,
1138 false,
1139 false,
1140 false,
1142 nullptr,
1143 nullptr) != nullptr);
1144
1145 if (!ok) {
1146 BKE_report(op->reports, RPT_ERROR, "Failed to create window");
1147 return OPERATOR_CANCELLED;
1148 }
1149 return OPERATOR_FINISHED;
1150}
1151
1153{
1154 wmWindow *win_src = CTX_wm_window(C);
1155
1156 bool ok = (wm_window_copy_test(C, win_src, true, false) != nullptr);
1157 if (!ok) {
1158 BKE_report(op->reports, RPT_ERROR, "Failed to create window");
1159 return OPERATOR_CANCELLED;
1160 }
1161 return OPERATOR_FINISHED;
1162}
1163
1165{
1166 wmWindow *window = CTX_wm_window(C);
1167
1168 if (G.background) {
1169 return OPERATOR_CANCELLED;
1170 }
1171
1173 static_cast<GHOST_WindowHandle>(window->ghostwin));
1175 GHOST_SetWindowState(static_cast<GHOST_WindowHandle>(window->ghostwin),
1177 }
1178 else {
1179 GHOST_SetWindowState(static_cast<GHOST_WindowHandle>(window->ghostwin),
1181 }
1182
1183 return OPERATOR_FINISHED;
1184}
1185
1188/* -------------------------------------------------------------------- */
1193{
1194 float fac = GHOST_GetNativePixelSize(static_cast<GHOST_WindowHandle>(win->ghostwin));
1195 *x *= fac;
1196
1197 *y = (win->sizey - 1) - *y;
1198 *y *= fac;
1199}
1200
1202{
1203 float fac = GHOST_GetNativePixelSize(static_cast<GHOST_WindowHandle>(win->ghostwin));
1204
1205 *x /= fac;
1206 *y /= fac;
1207 *y = win->sizey - *y - 1;
1208}
1209
1211{
1212 GHOST_ScreenToClient(static_cast<GHOST_WindowHandle>(win->ghostwin), *x, *y, x, y);
1214}
1215
1217{
1219 GHOST_ClientToScreen(static_cast<GHOST_WindowHandle>(win->ghostwin), *x, *y, x, y);
1220}
1221
1222bool wm_cursor_position_get(wmWindow *win, int *r_x, int *r_y)
1223{
1224 if (UNLIKELY(G.f & G_FLAG_EVENT_SIMULATE)) {
1225 *r_x = win->eventstate->xy[0];
1226 *r_y = win->eventstate->xy[1];
1227 return true;
1228 }
1229
1231 g_system, static_cast<GHOST_WindowHandle>(win->ghostwin), r_x, r_y) == GHOST_kSuccess)
1232 {
1234 return true;
1235 }
1236
1237 return false;
1238}
1239
1242{
1243 uint8_t result = 0;
1244 for (int i = 0; i < ARRAY_SIZE(g_modifier_table); i++) {
1245 bool val = false;
1247 if (val) {
1248 result |= g_modifier_table[i].flag;
1249 }
1250 }
1251 return result;
1252}
1253
1255{
1256 BLI_assert(ELEM(wm->windrawable, nullptr, win));
1257
1258 wm->windrawable = win;
1259 if (activate) {
1260 GHOST_ActivateWindowDrawingContext(static_cast<GHOST_WindowHandle>(win->ghostwin));
1261 }
1262 GPU_context_active_set(static_cast<GPUContext *>(win->gpuctx));
1263}
1264
1266{
1267 if (wm->windrawable) {
1268 wm->windrawable = nullptr;
1269 }
1270}
1271
1273{
1275
1276 if (win != wm->windrawable && win->ghostwin) {
1277 // win->lmbut = 0; /* Keeps hanging when mouse-pressed while other window opened. */
1279
1280 if (G.debug & G_DEBUG_EVENTS) {
1281 printf("%s: set drawable %d\n", __func__, win->winid);
1282 }
1283
1284 wm_window_set_drawable(wm, win, true);
1285 }
1286
1287 if (win->ghostwin) {
1288 /* This can change per window. */
1289 WM_window_set_dpi(win);
1290 }
1291}
1292
1294{
1297 wmWindowManager *wm = static_cast<wmWindowManager *>(G_MAIN->wm.first);
1298
1299 if (wm == nullptr) {
1300 return;
1301 }
1302 wmWindow *win = wm->windrawable;
1303
1304 if (win && win->ghostwin) {
1306 wm_window_set_drawable(wm, win, true);
1307 }
1308}
1309
1310#ifndef NDEBUG
1315static void ghost_event_proc_timestamp_warning(GHOST_EventHandle ghost_event)
1316{
1317 /* NOTE: The following time constants can be tweaked if they're reporting false positives. */
1318
1319 /* The reference event time-stamp must have happened in this time-frame. */
1320 constexpr uint64_t event_time_ok_ms = 1000;
1321 /* The current event time-stamp must be outside this time-frame to be considered an error. */
1322 constexpr uint64_t event_time_error_ms = 5000;
1323
1324 static uint64_t event_ms_ref_last = std::numeric_limits<uint64_t>::max();
1325 const uint64_t event_ms = GHOST_GetEventTime(ghost_event);
1326 const uint64_t event_ms_ref = event_ms_ref_last;
1327
1328 /* Assign first (allow early returns). */
1329 event_ms_ref_last = event_ms;
1330
1331 if (event_ms_ref == std::numeric_limits<uint64_t>::max()) {
1332 return;
1333 }
1334 /* Check the events are recent enough to be used for testing. */
1335 const uint64_t now_ms = GHOST_GetMilliSeconds(g_system);
1336 /* Ensure the reference time occurred in the last #event_time_ok_ms.
1337 * If not, the reference time it's self may be a bad time-stamp. */
1338 if (event_ms_ref < event_time_error_ms || (event_ms_ref < (now_ms - event_time_ok_ms)) ||
1339 (event_ms_ref > (now_ms + event_time_ok_ms)))
1340 {
1341 /* Skip, the reference time not recent enough to be used. */
1342 return;
1343 }
1344
1345 /* NOTE: Regarding time-stamps from the future.
1346 * Generally this shouldn't happen but may do depending on the kinds of events.
1347 * Different input methods may detect and trigger events in a way that wont ensure
1348 * monotonic event times, so only consider this an error for large time deltas. */
1349 double time_delta = 0.0;
1350 if (event_ms < (event_ms_ref - event_time_error_ms)) {
1351 /* New event time is after (to be expected). */
1352 time_delta = double(now_ms - event_ms) / -1000.0;
1353 }
1354 else if (event_ms > (event_ms_ref + event_time_error_ms)) {
1355 /* New event time is before (unexpected but not an error). */
1356 time_delta = double(event_ms - now_ms) / 1000.0;
1357 }
1358 else {
1359 /* Time is in range. */
1360 return;
1361 }
1362
1363 const char *time_unit = "seconds";
1364 const struct {
1365 const char *unit;
1366 double scale;
1367 } unit_table[] = {{"minutes", 60}, {"hours", 60}, {"days", 24}, {"weeks", 7}, {"years", 52}};
1368 for (int i = 0; i < ARRAY_SIZE(unit_table); i++) {
1369 if (std::abs(time_delta) <= unit_table[i].scale) {
1370 break;
1371 }
1372 time_delta /= unit_table[i].scale;
1373 time_unit = unit_table[i].unit;
1374 }
1375
1376 fprintf(stderr,
1377 "GHOST: suspicious time-stamp from far in the %s: %.2f %s, "
1378 "absolute value is %" PRIu64 ", current time is %" PRIu64 ", for type %d\n",
1379 time_delta < 0.0f ? "past" : "future",
1380 std::abs(time_delta),
1381 time_unit,
1382 event_ms,
1383 now_ms,
1384 int(GHOST_GetEventType(ghost_event)));
1385}
1386#endif /* !NDEBUG */
1387
1393static bool ghost_event_proc(GHOST_EventHandle ghost_event, GHOST_TUserDataPtr C_void_ptr)
1394{
1395 bContext *C = static_cast<bContext *>(C_void_ptr);
1397 GHOST_TEventType type = GHOST_GetEventType(ghost_event);
1398
1399 GHOST_WindowHandle ghostwin = GHOST_GetEventWindow(ghost_event);
1400
1401#ifndef NDEBUG
1403#endif
1404
1405 if (type == GHOST_kEventQuitRequest) {
1406 /* Find an active window to display quit dialog in. */
1407 wmWindow *win;
1408 if (ghostwin && GHOST_ValidWindow(g_system, ghostwin)) {
1409 win = static_cast<wmWindow *>(GHOST_GetWindowUserData(ghostwin));
1410 }
1411 else {
1412 win = wm->winactive;
1413 }
1414
1415 /* Display quit dialog or quit immediately. */
1416 if (win) {
1418 }
1419 else {
1421 }
1422 return true;
1423 }
1424
1425 GHOST_TEventDataPtr data = GHOST_GetEventData(ghost_event);
1426 const uint64_t event_time_ms = GHOST_GetEventTime(ghost_event);
1427
1428 /* Ghost now can call this function for life resizes,
1429 * but it should return if WM didn't initialize yet.
1430 * Can happen on file read (especially full size window). */
1431 if ((wm->init_flag & WM_INIT_FLAG_WINDOW) == 0) {
1432 return true;
1433 }
1434 if (!ghostwin) {
1435 /* XXX: should be checked, why are we getting an event here, and what is it? */
1436 puts("<!> event has no window");
1437 return true;
1438 }
1439 if (!GHOST_ValidWindow(g_system, ghostwin)) {
1440 /* XXX: should be checked, why are we getting an event here, and what is it? */
1441 puts("<!> event has invalid window");
1442 return true;
1443 }
1444
1445 wmWindow *win = static_cast<wmWindow *>(GHOST_GetWindowUserData(ghostwin));
1446
1447 switch (type) {
1449 wm_window_update_eventstate_modifiers_clear(wm, win, event_time_ms);
1450
1451 wm_event_add_ghostevent(wm, win, type, data, event_time_ms);
1452 win->active = 0;
1453 break;
1454 }
1456 /* Ensure the event state matches modifiers (window was inactive). */
1457 wm_window_update_eventstate_modifiers(wm, win, event_time_ms);
1458
1459 /* Entering window, update mouse position (without sending an event). */
1461
1462 /* No context change! `C->wm->windrawable` is drawable, or for area queues. */
1463 wm->winactive = win;
1464 win->active = 1;
1465
1466 /* Zero the `keymodifier`, it hangs on hotkeys that open windows otherwise. */
1467 win->eventstate->keymodifier = 0;
1468
1469 win->addmousemove = 1; /* Enables highlighted buttons. */
1470
1471 wm_window_make_drawable(wm, win);
1472
1473 /* Window might be focused by mouse click in configuration of window manager
1474 * when focus is not following mouse
1475 * click could have been done on a button and depending on window manager settings
1476 * click would be passed to blender or not, but in any case button under cursor
1477 * should be activated, so at max next click on button without moving mouse
1478 * would trigger its handle function
1479 * currently it seems to be common practice to generate new event for, but probably
1480 * we'll need utility function for this? (sergey)
1481 */
1482 wmEvent event;
1483 wm_event_init_from_window(win, &event);
1484 event.type = MOUSEMOVE;
1485 event.val = KM_NOTHING;
1486 copy_v2_v2_int(event.prev_xy, event.xy);
1487 event.flag = eWM_EventFlag(0);
1488
1489 wm_event_add(win, &event);
1490
1491 break;
1492 }
1494 wm_window_close(C, wm, win);
1495 break;
1496 }
1498 if (G.debug & G_DEBUG_EVENTS) {
1499 printf("%s: ghost redraw %d\n", __func__, win->winid);
1500 }
1501
1502 wm_window_make_drawable(wm, win);
1503 WM_event_add_notifier_ex(wm, win, NC_WINDOW, nullptr);
1504
1505 break;
1506 }
1508 if (G.debug & G_DEBUG_EVENTS) {
1509 printf("%s: ghost redraw decor %d\n", __func__, win->winid);
1510 }
1511
1512 wm_window_make_drawable(wm, win);
1513#if 0
1514 /* NOTE(@ideasman42): Ideally we could swap-buffers to avoid a full redraw.
1515 * however this causes window flickering on resize with LIBDECOR under WAYLAND. */
1517#else
1518 WM_event_add_notifier_ex(wm, win, NC_WINDOW, nullptr);
1519#endif
1520
1521 break;
1522 }
1526 static_cast<GHOST_WindowHandle>(win->ghostwin));
1527 win->windowstate = state;
1528
1529 WM_window_set_dpi(win);
1530
1531 /* WIN32: gives undefined window size when minimized. */
1533 /*
1534 * Ghost sometimes send size or move events when the window hasn't changed.
1535 * One case of this is using COMPIZ on Linux.
1536 * To alleviate the problem we ignore all such event here.
1537 *
1538 * It might be good to eventually do that at GHOST level, but that is for another time.
1539 */
1541 const bScreen *screen = WM_window_get_active_screen(win);
1542
1543 /* Debug prints. */
1544 if (G.debug & G_DEBUG_EVENTS) {
1545 const char *state_str;
1546 state = GHOST_GetWindowState(static_cast<GHOST_WindowHandle>(win->ghostwin));
1547
1549 state_str = "normal";
1550 }
1551 else if (state == GHOST_kWindowStateMinimized) {
1552 state_str = "minimized";
1553 }
1554 else if (state == GHOST_kWindowStateMaximized) {
1555 state_str = "maximized";
1556 }
1557 else if (state == GHOST_kWindowStateFullScreen) {
1558 state_str = "full-screen";
1559 }
1560 else {
1561 state_str = "<unknown>";
1562 }
1563
1564 printf("%s: window %d state = %s\n", __func__, win->winid, state_str);
1565
1566 if (type != GHOST_kEventWindowSize) {
1567 printf("win move event pos %d %d size %d %d\n",
1568 win->posx,
1569 win->posy,
1570 win->sizex,
1571 win->sizey);
1572 }
1573 }
1574
1575 wm_window_make_drawable(wm, win);
1576 BKE_icon_changed(screen->id.icon_id);
1577 WM_event_add_notifier_ex(wm, win, NC_SCREEN | NA_EDITED, nullptr);
1578 WM_event_add_notifier_ex(wm, win, NC_WINDOW | NA_EDITED, nullptr);
1579
1580#if defined(__APPLE__) || defined(WIN32)
1581 /* MACOS and WIN32 don't return to the main-loop while resize. */
1582 int dummy_sleep_ms = 0;
1583 wm_window_timers_process(C, &dummy_sleep_ms);
1586 wm_draw_update(C);
1587#endif
1588 }
1589 }
1590 break;
1591 }
1592
1594 WM_window_set_dpi(win);
1595 /* Font's are stored at each DPI level, without this we can easy load 100's of fonts. */
1597
1598 WM_main_add_notifier(NC_WINDOW, nullptr); /* Full redraw. */
1599 WM_main_add_notifier(NC_SCREEN | NA_EDITED, nullptr); /* Refresh region sizes. */
1600 break;
1601 }
1602
1604 const char *path = static_cast<const char *>(data);
1605
1606 if (path) {
1607 wmOperatorType *ot = WM_operatortype_find("WM_OT_open_mainfile", false);
1608 /* Operator needs a valid window in context, ensures it is correctly set. */
1609 CTX_wm_window_set(C, win);
1610
1611 PointerRNA props_ptr;
1613 RNA_string_set(&props_ptr, "filepath", path);
1614 RNA_boolean_set(&props_ptr, "display_file_selector", false);
1615 WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &props_ptr, nullptr);
1616 WM_operator_properties_free(&props_ptr);
1617
1618 CTX_wm_window_set(C, nullptr);
1619 }
1620 break;
1621 }
1623 const GHOST_TEventDragnDropData *ddd = static_cast<const GHOST_TEventDragnDropData *>(data);
1624
1625 /* Ensure the event state matches modifiers (window was inactive). */
1626 wm_window_update_eventstate_modifiers(wm, win, event_time_ms);
1627 /* Entering window, update mouse position (without sending an event). */
1629
1630 wmEvent event;
1631 wm_event_init_from_window(win, &event); /* Copy last state, like mouse coords. */
1632
1633 /* Activate region. */
1634 event.type = MOUSEMOVE;
1635 event.val = KM_NOTHING;
1636 copy_v2_v2_int(event.prev_xy, event.xy);
1637
1638 copy_v2_v2_int(event.xy, &ddd->x);
1639 wm_cursor_position_from_ghost_screen_coords(win, &event.xy[0], &event.xy[1]);
1640
1641 /* The values from #wm_window_update_eventstate may not match (under WAYLAND they don't)
1642 * Write this into the event state. */
1643 copy_v2_v2_int(win->eventstate->xy, event.xy);
1644
1645 event.flag = eWM_EventFlag(0);
1646
1647 /* No context change! `C->wm->windrawable` is drawable, or for area queues. */
1648 wm->winactive = win;
1649 win->active = 1;
1650
1651 wm_event_add(win, &event);
1652
1653 /* Make blender drop event with custom data pointing to wm drags. */
1654 event.type = EVT_DROP;
1655 event.val = KM_RELEASE;
1656 event.custom = EVT_DATA_DRAGDROP;
1657 event.customdata = &wm->drags;
1658 event.customdata_free = true;
1659
1660 wm_event_add(win, &event);
1661
1662 // printf("Drop detected\n");
1663
1664 /* Add drag data to wm for paths. */
1665
1667 const GHOST_TStringArray *stra = static_cast<const GHOST_TStringArray *>(ddd->data);
1668
1669 if (stra->count) {
1670 CLOG_INFO(WM_LOG_EVENTS, 1, "Drop %d files:", stra->count);
1671 for (const char *path : blender::Span((char **)stra->strings, stra->count)) {
1672 CLOG_INFO(WM_LOG_EVENTS, 1, "%s", path);
1673 }
1674 /* Try to get icon type from extension of the first path. */
1675 int icon = ED_file_extension_icon((char *)stra->strings[0]);
1677 blender::Span((char **)stra->strings, stra->count));
1678 WM_event_start_drag(C, icon, WM_DRAG_PATH, path_data, WM_DRAG_NOP);
1679 /* Void pointer should point to string, it makes a copy. */
1680 }
1681 }
1682 else if (ddd->dataType == GHOST_kDragnDropTypeString) {
1683 /* Drop an arbitrary string. */
1684 std::string *str = MEM_new<std::string>(__func__, static_cast<const char *>(ddd->data));
1686 }
1687
1688 break;
1689 }
1691 /* Only update if the actual pixel size changes. */
1692 float prev_pixelsize = U.pixelsize;
1693 WM_window_set_dpi(win);
1694
1695 if (U.pixelsize != prev_pixelsize) {
1697
1698 /* Close all popups since they are positioned with the pixel
1699 * size baked in and it's difficult to correct them. */
1700 CTX_wm_window_set(C, win);
1702 CTX_wm_window_set(C, nullptr);
1703
1704 wm_window_make_drawable(wm, win);
1705
1706 WM_event_add_notifier_ex(wm, win, NC_SCREEN | NA_EDITED, nullptr);
1707 WM_event_add_notifier_ex(wm, win, NC_WINDOW | NA_EDITED, nullptr);
1708 }
1709
1710 break;
1711 }
1713 case GHOST_kEventButtonUp: {
1714 if (win->active == 0) {
1715 /* Entering window, update cursor/tablet state & modifiers.
1716 * (ghost sends win-activate *after* the mouse-click in window!). */
1717 wm_window_update_eventstate_modifiers(wm, win, event_time_ms);
1719 }
1720
1721 wm_event_add_ghostevent(wm, win, type, data, event_time_ms);
1722 break;
1723 }
1724 default: {
1725 wm_event_add_ghostevent(wm, win, type, data, event_time_ms);
1726 break;
1727 }
1728 }
1729
1730 return true;
1731}
1732
1742static bool wm_window_timers_process(const bContext *C, int *sleep_us_p)
1743{
1744 Main *bmain = CTX_data_main(C);
1746 const double time = BLI_time_now_seconds();
1747 bool has_event = false;
1748
1749 const int sleep_us = *sleep_us_p;
1750 /* The nearest time an active timer is scheduled to run. */
1751 double ntime_min = DBL_MAX;
1752
1753 /* Mutable in case the timer gets removed. */
1755 if (wt->flags & WM_TIMER_TAGGED_FOR_REMOVAL) {
1756 continue;
1757 }
1758 if (wt->sleep == true) {
1759 continue;
1760 }
1761
1762 /* Future timer, update nearest time & skip. */
1763 if (wt->time_next >= time) {
1764 if ((has_event == false) && (sleep_us != 0)) {
1765 /* The timer is not ready to run but may run shortly. */
1766 if (wt->time_next < ntime_min) {
1767 ntime_min = wt->time_next;
1768 }
1769 }
1770 continue;
1771 }
1772
1773 wt->time_delta = time - wt->time_last;
1774 wt->time_duration += wt->time_delta;
1775 wt->time_last = time;
1776
1777 wt->time_next = wt->time_start;
1778 if (wt->time_step != 0.0f) {
1779 wt->time_next += wt->time_step * ceil(wt->time_duration / wt->time_step);
1780 }
1781
1782 if (wt->event_type == TIMERJOBS) {
1783 wm_jobs_timer(wm, wt);
1784 }
1785 else if (wt->event_type == TIMERAUTOSAVE) {
1786 wm_autosave_timer(bmain, wm, wt);
1787 }
1788 else if (wt->event_type == TIMERNOTIFIER) {
1789 WM_main_add_notifier(POINTER_AS_UINT(wt->customdata), nullptr);
1790 }
1791 else if (wmWindow *win = wt->win) {
1792 wmEvent event;
1793 wm_event_init_from_window(win, &event);
1794
1795 event.type = wt->event_type;
1796 event.val = KM_NOTHING;
1797 event.keymodifier = 0;
1798 event.flag = eWM_EventFlag(0);
1799 event.custom = EVT_DATA_TIMER;
1800 event.customdata = wt;
1801 wm_event_add(win, &event);
1802
1803 has_event = true;
1804 }
1805 }
1806
1807 if ((has_event == false) && (sleep_us != 0) && (ntime_min != DBL_MAX)) {
1808 /* Clamp the sleep time so next execution runs earlier (if necessary).
1809 * Use `ceil` so the timer is guarantee to be ready to run (not always the case with rounding).
1810 * Even though using `floor` or `round` is more responsive,
1811 * it causes CPU intensive loops that may run until the timer is reached, see: #111579. */
1812 const double microseconds = 1000000.0;
1813 const double sleep_sec = double(sleep_us) / microseconds;
1814 const double sleep_sec_next = ntime_min - time;
1815
1816 if (sleep_sec_next < sleep_sec) {
1817 *sleep_us_p = int(std::ceil(sleep_sec_next * microseconds));
1818 }
1819 }
1820
1821 /* Effectively delete all timers marked for removal. */
1823
1824 return has_event;
1825}
1826
1828{
1831
1832 bool has_event = GHOST_ProcessEvents(g_system, false); /* `false` is no wait. */
1833
1834 if (has_event) {
1836 }
1837
1838 /* When there is no event, sleep 5 milliseconds not to use too much CPU when idle. */
1839 const int sleep_us_default = 5000;
1840 int sleep_us = has_event ? 0 : sleep_us_default;
1841 has_event |= wm_window_timers_process(C, &sleep_us);
1842#ifdef WITH_XR_OPENXR
1843 /* XR events don't use the regular window queues. So here we don't only trigger
1844 * processing/dispatching but also handling. */
1845 has_event |= wm_xr_events_handle(CTX_wm_manager(C));
1846#endif
1848
1849 /* Skip sleeping when simulating events so tests don't idle unnecessarily as simulated
1850 * events are typically generated from a timer that runs in the main loop. */
1851 if ((has_event == false) && (sleep_us != 0) && !(G.f & G_FLAG_EVENT_SIMULATE)) {
1852 if (sleep_us == sleep_us_default) {
1853 /* NOTE(@ideasman42): prefer #BLI_time_sleep_ms over `sleep_for(..)` in the common case
1854 * because this function uses lower resolution (millisecond) resolution sleep timers
1855 * which are tried & true for the idle loop. We could move to C++ `sleep_for(..)`
1856 * if this works well on all platforms but this needs further testing. */
1857 BLI_time_sleep_ms(sleep_us_default / 1000);
1858 }
1859 else {
1860 /* The time was shortened to resume for the upcoming timer, use a high resolution sleep.
1861 * Mainly happens during animation playback but could happen immediately before any timer.
1862 *
1863 * NOTE(@ideasman42): At time of writing Windows-10-22H2 doesn't give higher precision sleep.
1864 * Keep the functionality as it doesn't have noticeable down sides either. */
1865 std::this_thread::sleep_for(std::chrono::microseconds(sleep_us));
1866 }
1867 }
1868}
1869
1872/* -------------------------------------------------------------------- */
1877{
1878 if (g_system) {
1879 return;
1880 }
1881
1882 BLI_assert(C != nullptr);
1883 BLI_assert_msg(!G.background, "Use wm_ghost_init_background instead");
1884
1885 GHOST_EventConsumerHandle consumer;
1886
1888
1890
1893
1894 if (UNLIKELY(g_system == nullptr)) {
1895 /* GHOST will have reported the back-ends that failed to load. */
1896 fprintf(stderr, "GHOST: unable to initialize, exiting!\n");
1897 /* This will leak memory, it's preferable to crashing. */
1898 exit(EXIT_FAILURE);
1899 }
1900#if !(defined(WIN32) || defined(__APPLE__))
1902#endif
1903
1904 GHOST_Debug debug = {0};
1905 if (G.debug & G_DEBUG_GHOST) {
1906 debug.flags |= GHOST_kDebugDefault;
1907 }
1908 if (G.debug & G_DEBUG_WINTAB) {
1909 debug.flags |= GHOST_kDebugWintab;
1910 }
1912
1914
1917 }
1918
1920}
1921
1923{
1924 /* TODO: move this to `wm_init_exit.cc`. */
1925
1926 if (g_system) {
1927 return;
1928 }
1929
1931
1934
1935 GHOST_Debug debug = {0};
1936 if (G.debug & G_DEBUG_GHOST) {
1937 debug.flags |= GHOST_kDebugDefault;
1938 }
1940}
1941
1943{
1944 if (g_system) {
1946 }
1947 g_system = nullptr;
1948}
1949
1950const char *WM_ghost_backend()
1951{
1952#if !(defined(WIN32) || defined(__APPLE__))
1953 return g_system_backend_id ? g_system_backend_id : "NONE";
1954#else
1955 /* While this could be supported, at the moment it's only needed with GHOST X11/WAYLAND
1956 * to check which was selected and the API call may be removed after that's no longer needed.
1957 * Use dummy values to prevent this being used on other systems. */
1958 return g_system ? "DEFAULT" : "NONE";
1959#endif
1960}
1961
1963{
1964 switch (gpu_backend) {
1965 case GPU_BACKEND_NONE:
1967 case GPU_BACKEND_ANY:
1968 case GPU_BACKEND_OPENGL:
1969#ifdef WITH_OPENGL_BACKEND
1970 return GHOST_kDrawingContextTypeOpenGL;
1971#endif
1974 case GPU_BACKEND_VULKAN:
1975#ifdef WITH_VULKAN_BACKEND
1976 return GHOST_kDrawingContextTypeVulkan;
1977#endif
1980 case GPU_BACKEND_METAL:
1981#ifdef WITH_METAL_BACKEND
1982 return GHOST_kDrawingContextTypeMetal;
1983#endif
1986 }
1987
1988 /* Avoid control reaches end of non-void function compilation warning, which could be promoted
1989 * to error. */
1992}
1993
1994static uiBlock *block_create_opengl_usage_warning(bContext *C, ARegion *region, void * /*arg1*/)
1995{
1996 uiBlock *block = UI_block_begin(C, region, "autorun_warning_popup", UI_EMBOSS);
1999
2000 uiLayout *layout = uiItemsAlertBox(block, 44, ALERT_ICON_ERROR);
2001
2002 /* Title and explanation text. */
2003 uiLayout *col = uiLayoutColumn(layout, false);
2004 uiItemL_ex(col, RPT_("Python script uses OpenGL for drawing"), ICON_NONE, true, false);
2005 uiItemL(col, RPT_("This may lead to unexpected behavior"), ICON_NONE);
2006 uiItemL(col,
2007 RPT_("One of the add-ons or scripts is using OpenGL and will not work correct on Metal"),
2008 ICON_NONE);
2009 uiItemL(col,
2010 RPT_("Please contact the developer of the add-on to migrate to use 'gpu' module"),
2011 ICON_NONE);
2012 if (G.opengl_deprecation_usage_filename) {
2013 char location[1024];
2014 SNPRINTF(
2015 location, "%s:%d", G.opengl_deprecation_usage_filename, G.opengl_deprecation_usage_lineno);
2016 uiItemL(col, location, ICON_NONE);
2017 }
2018 uiItemL(col, RPT_("See system tab in preferences to switch to OpenGL backend"), ICON_NONE);
2019
2020 uiItemS(layout);
2021
2023
2024 return block;
2025}
2026
2028{
2029 static bool message_shown = false;
2030
2031 /* Exit when no failure detected. */
2032 if (!G.opengl_deprecation_usage_detected) {
2033 return;
2034 }
2035
2036 /* Have we already shown a message during this Blender session. `bgl` calls are done in a draw
2037 * handler that will run many times. */
2038 if (message_shown) {
2039 return;
2040 }
2041
2043 wmWindow *win = static_cast<wmWindow *>((wm->winactive) ? wm->winactive : wm->windows.first);
2044
2045 BKE_report(&wm->runtime->reports,
2046 RPT_ERROR,
2047 "One of the add-ons or scripts is using OpenGL and will not work correct on Metal. "
2048 "Please contact the developer of the add-on to migrate to use 'gpu' module");
2049
2050 if (win) {
2051 /* We want this warning on the Main window, not a child window even if active. See #118765. */
2052 if (win->parent) {
2053 win = win->parent;
2054 }
2055
2056 wmWindow *prevwin = CTX_wm_window(C);
2057 CTX_wm_window_set(C, win);
2059 CTX_wm_window_set(C, prevwin);
2060 }
2061
2062 message_shown = true;
2063}
2064
2065static uiBlock *block_create_gpu_backend_fallback(bContext *C, ARegion *region, void * /*arg1*/)
2066{
2067 uiBlock *block = UI_block_begin(C, region, "autorun_warning_popup", UI_EMBOSS);
2070
2071 uiLayout *layout = uiItemsAlertBox(block, 44, ALERT_ICON_ERROR);
2072
2073 /* Title and explanation text. */
2074 uiLayout *col = uiLayoutColumn(layout, false);
2075 uiItemL_ex(
2076 col, RPT_("Failed to load using Vulkan, using OpenGL instead."), ICON_NONE, true, false);
2077 uiItemL(col, RPT_(""), ICON_NONE);
2078 uiItemL(col, RPT_("Updating GPU drivers may solve this issue."), ICON_NONE);
2079 uiItemL(col,
2080 RPT_("The graphics backend can be changed in the System section of the Preferences."),
2081 ICON_NONE);
2082
2083 uiItemS(layout);
2084
2086
2087 return block;
2088}
2089
2091{
2092 if (!bool(G.f & G_FLAG_GPU_BACKEND_FALLBACK)) {
2093 return;
2094 }
2095
2096 /* Have we already shown a message during this Blender session. */
2097 if (bool(G.f & G_FLAG_GPU_BACKEND_FALLBACK_QUIET)) {
2098 return;
2099 }
2101
2103 wmWindow *win = static_cast<wmWindow *>((wm->winactive) ? wm->winactive : wm->windows.first);
2104
2105 if (win) {
2106 /* We want this warning on the Main window, not a child window even if active. See #118765. */
2107 if (win->parent) {
2108 win = win->parent;
2109 }
2110
2111 wmWindow *prevwin = CTX_wm_window(C);
2112 CTX_wm_window_set(C, win);
2114 CTX_wm_window_set(C, prevwin);
2115 }
2116}
2117
2119{
2121 if (flag != 0) {
2122 return flag;
2123 }
2125
2126 const GHOST_TCapabilityFlag ghost_flag = GHOST_GetCapabilities();
2127 if (ghost_flag & GHOST_kCapabilityCursorWarp) {
2129 }
2130 if (ghost_flag & GHOST_kCapabilityWindowPosition) {
2132 }
2133 if (ghost_flag & GHOST_kCapabilityPrimaryClipboard) {
2135 }
2136 if (ghost_flag & GHOST_kCapabilityGPUReadFrontBuffer) {
2138 }
2139 if (ghost_flag & GHOST_kCapabilityClipboardImages) {
2141 }
2142 if (ghost_flag & GHOST_kCapabilityDesktopSample) {
2144 }
2145 if (ghost_flag & GHOST_kCapabilityInputIME) {
2147 }
2150 }
2151
2152 return flag;
2153}
2154
2157/* -------------------------------------------------------------------- */
2161void WM_event_timer_sleep(wmWindowManager *wm, wmWindow * /*win*/, wmTimer *timer, bool do_sleep)
2162{
2163 /* Extra security check. */
2164 if (BLI_findindex(&wm->timers, timer) == -1) {
2165 return;
2166 }
2167 /* It's disputable if this is needed, when tagged for removal,
2168 * the sleep value won't be used anyway. */
2170 return;
2171 }
2172 timer->sleep = do_sleep;
2173}
2174
2176 wmWindow *win,
2177 const int event_type,
2178 const double time_step)
2179{
2180 BLI_assert(ISTIMER(event_type));
2181
2182 wmTimer *wt = static_cast<wmTimer *>(MEM_callocN(sizeof(wmTimer), "window timer"));
2183 BLI_assert(time_step >= 0.0f);
2184
2185 wt->event_type = event_type;
2187 wt->time_next = wt->time_last + time_step;
2188 wt->time_start = wt->time_last;
2189 wt->time_step = time_step;
2190 wt->win = win;
2191
2192 BLI_addtail(&wm->timers, wt);
2193
2194 return wt;
2195}
2196
2198 wmWindow *win,
2199 const uint type,
2200 const double time_step)
2201{
2202 wmTimer *wt = static_cast<wmTimer *>(MEM_callocN(sizeof(wmTimer), "window timer"));
2203 BLI_assert(time_step >= 0.0f);
2204
2207 wt->time_next = wt->time_last + time_step;
2208 wt->time_start = wt->time_last;
2209 wt->time_step = time_step;
2210 wt->win = win;
2211 wt->customdata = POINTER_FROM_UINT(type);
2213
2214 BLI_addtail(&wm->timers, wt);
2215
2216 return wt;
2217}
2218
2220{
2222 if ((wt->flags & WM_TIMER_TAGGED_FOR_REMOVAL) == 0) {
2223 continue;
2224 }
2225
2226 /* Actual removal and freeing of the timer. */
2227 BLI_remlink(&wm->timers, wt);
2228 MEM_freeN(wt);
2229 }
2230}
2231
2233{
2234 if (timer->customdata != nullptr && (timer->flags & WM_TIMER_NO_FREE_CUSTOM_DATA) == 0) {
2236 timer->customdata = nullptr;
2237 }
2238}
2239
2241{
2243 "This should only be called when freeing the window-manager");
2244 while (wmTimer *timer = static_cast<wmTimer *>(BLI_pophead(&wm->timers))) {
2247 }
2248}
2249
2251{
2252 /* Extra security check. */
2253 if (BLI_findindex(&wm->timers, timer) == -1) {
2254 return;
2255 }
2256
2258
2259 /* Clear existing references to the timer. */
2260 if (wm->runtime->reports.reporttimer == timer) {
2261 wm->runtime->reports.reporttimer = nullptr;
2262 }
2263 /* There might be events in queue with this timer as customdata. */
2264 LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
2265 LISTBASE_FOREACH (wmEvent *, event, &win->event_queue) {
2266 if (event->customdata == timer) {
2267 event->customdata = nullptr;
2268 event->type = EVENT_NONE; /* Timer users customdata, don't want `nullptr == nullptr`. */
2269 }
2270 }
2271 }
2272
2273 /* Immediately free `customdata` if requested, so that invalid usages of that data after
2274 * calling `WM_event_timer_remove` can be easily spotted (through ASAN errors e.g.). */
2276}
2277
2283
2286/* -------------------------------------------------------------------- */
2294struct {
2295 char *buffers[2];
2297
2299{
2300 if (g_wm_clipboard_text_simulate == nullptr) {
2301 return;
2302 }
2303 for (int i = 0; i < ARRAY_SIZE(g_wm_clipboard_text_simulate->buffers); i++) {
2304 char *buf = g_wm_clipboard_text_simulate->buffers[i];
2305 if (buf) {
2306 MEM_freeN(buf);
2307 }
2308 }
2311}
2312
2313static char *wm_clipboard_text_get_impl(bool selection)
2314{
2315 if (UNLIKELY(G.f & G_FLAG_EVENT_SIMULATE)) {
2316 if (g_wm_clipboard_text_simulate == nullptr) {
2317 return nullptr;
2318 }
2319 const char *buf_src = g_wm_clipboard_text_simulate->buffers[int(selection)];
2320 if (buf_src == nullptr) {
2321 return nullptr;
2322 }
2323 size_t size = strlen(buf_src) + 1;
2324 char *buf = static_cast<char *>(malloc(size));
2325 memcpy(buf, buf_src, size);
2326 return buf;
2327 }
2328
2329 return GHOST_getClipboard(selection);
2330}
2331
2332static void wm_clipboard_text_set_impl(const char *buf, bool selection)
2333{
2334 if (UNLIKELY(G.f & G_FLAG_EVENT_SIMULATE)) {
2335 if (g_wm_clipboard_text_simulate == nullptr) {
2337 MEM_callocN(sizeof(*g_wm_clipboard_text_simulate), __func__));
2338 }
2339 char **buf_src_p = &(g_wm_clipboard_text_simulate->buffers[int(selection)]);
2340 MEM_SAFE_FREE(*buf_src_p);
2341 *buf_src_p = BLI_strdup(buf);
2342 return;
2343 }
2344
2345 GHOST_putClipboard(buf, selection);
2346}
2347
2350/* -------------------------------------------------------------------- */
2354static char *wm_clipboard_text_get_ex(bool selection,
2355 int *r_len,
2356 const bool ensure_utf8,
2357 const bool firstline)
2358{
2359 if (G.background) {
2360 *r_len = 0;
2361 return nullptr;
2362 }
2363
2364 char *buf = wm_clipboard_text_get_impl(selection);
2365 if (!buf) {
2366 *r_len = 0;
2367 return nullptr;
2368 }
2369
2370 int buf_len = strlen(buf);
2371
2372 if (ensure_utf8) {
2373 /* TODO(@ideasman42): It would be good if unexpected byte sequences could be interpreted
2374 * instead of stripped - so mixed in characters (typically Latin1) aren't ignored.
2375 * Check on how Python bytes this, see: #PyC_UnicodeFromBytesAndSize,
2376 * there are clever ways to handle this although they increase the size of the buffer. */
2377 buf_len -= BLI_str_utf8_invalid_strip(buf, buf_len);
2378 }
2379
2380 /* Always convert from `\r\n` to `\n`. */
2381 char *newbuf = static_cast<char *>(MEM_mallocN(buf_len + 1, __func__));
2382 char *p2 = newbuf;
2383
2384 if (firstline) {
2385 /* Will return an over-allocated value in the case there are newlines. */
2386 for (char *p = buf; *p; p++) {
2387 if (!ELEM(*p, '\n', '\r')) {
2388 *(p2++) = *p;
2389 }
2390 else {
2391 break;
2392 }
2393 }
2394 }
2395 else {
2396 for (char *p = buf; *p; p++) {
2397 if (*p != '\r') {
2398 *(p2++) = *p;
2399 }
2400 }
2401 }
2402
2403 *p2 = '\0';
2404
2405 free(buf); /* GHOST uses regular malloc. */
2406
2407 *r_len = (p2 - newbuf);
2408
2409 return newbuf;
2410}
2411
2412char *WM_clipboard_text_get(bool selection, bool ensure_utf8, int *r_len)
2413{
2414 return wm_clipboard_text_get_ex(selection, r_len, ensure_utf8, false);
2415}
2416
2417char *WM_clipboard_text_get_firstline(bool selection, bool ensure_utf8, int *r_len)
2418{
2419 return wm_clipboard_text_get_ex(selection, r_len, ensure_utf8, true);
2420}
2421
2422void WM_clipboard_text_set(const char *buf, bool selection)
2423{
2424 if (!G.background) {
2425#ifdef _WIN32
2426 /* Do conversion from `\n` to `\r\n` on Windows. */
2427 const char *p;
2428 char *p2, *newbuf;
2429 int newlen = 0;
2430
2431 for (p = buf; *p; p++) {
2432 if (*p == '\n') {
2433 newlen += 2;
2434 }
2435 else {
2436 newlen++;
2437 }
2438 }
2439
2440 newbuf = static_cast<char *>(MEM_callocN(newlen + 1, "WM_clipboard_text_set"));
2441
2442 for (p = buf, p2 = newbuf; *p; p++, p2++) {
2443 if (*p == '\n') {
2444 *(p2++) = '\r';
2445 *p2 = '\n';
2446 }
2447 else {
2448 *p2 = *p;
2449 }
2450 }
2451 *p2 = '\0';
2452
2453 wm_clipboard_text_set_impl(newbuf, selection);
2454 MEM_freeN(newbuf);
2455#else
2456 wm_clipboard_text_set_impl(buf, selection);
2457#endif
2458 }
2459}
2460
2462{
2463 if (G.background) {
2464 return false;
2465 }
2466 return bool(GHOST_hasClipboardImage());
2467}
2468
2470{
2471 if (G.background) {
2472 return nullptr;
2473 }
2474
2475 int width, height;
2476
2477 uint8_t *rgba = (uint8_t *)GHOST_getClipboardImage(&width, &height);
2478 if (!rgba) {
2479 return nullptr;
2480 }
2481
2482 ImBuf *ibuf = IMB_allocFromBuffer(rgba, nullptr, width, height, 4);
2483 free(rgba);
2484
2485 return ibuf;
2486}
2487
2489{
2490 if (G.background) {
2491 return false;
2492 }
2493
2494 bool free_byte_buffer = false;
2495 if (ibuf->byte_buffer.data == nullptr) {
2496 /* Add a byte buffer if it does not have one. */
2497 IMB_rect_from_float(ibuf);
2498 free_byte_buffer = true;
2499 }
2500
2501 bool success = bool(GHOST_putClipboardImage((uint *)ibuf->byte_buffer.data, ibuf->x, ibuf->y));
2502
2503 if (free_byte_buffer) {
2504 /* Remove the byte buffer if we added it. */
2505 imb_freerectImBuf(ibuf);
2506 }
2507
2508 return success;
2509}
2510
2513/* -------------------------------------------------------------------- */
2517void WM_progress_set(wmWindow *win, float progress)
2518{
2519 /* In background mode we may have windows, but not actual GHOST windows. */
2520 if (win->ghostwin) {
2521 GHOST_SetProgressBar(static_cast<GHOST_WindowHandle>(win->ghostwin), progress);
2522 }
2523}
2524
2526{
2527 if (win->ghostwin) {
2528 GHOST_EndProgressBar(static_cast<GHOST_WindowHandle>(win->ghostwin));
2529 }
2530}
2531
2534/* -------------------------------------------------------------------- */
2538void wm_window_set_size(wmWindow *win, int width, int height)
2539{
2540 GHOST_SetClientSize(static_cast<GHOST_WindowHandle>(win->ghostwin), width, height);
2541}
2542
2545/* -------------------------------------------------------------------- */
2550{
2551 GHOST_SetWindowOrder(static_cast<GHOST_WindowHandle>(win->ghostwin), GHOST_kWindowOrderBottom);
2552}
2553
2555{
2556 /* Restore window if minimized. */
2557 if (GHOST_GetWindowState(static_cast<GHOST_WindowHandle>(win->ghostwin)) ==
2559 {
2560 GHOST_SetWindowState(static_cast<GHOST_WindowHandle>(win->ghostwin), GHOST_kWindowStateNormal);
2561 }
2562 GHOST_SetWindowOrder(static_cast<GHOST_WindowHandle>(win->ghostwin), GHOST_kWindowOrderTop);
2563}
2564
2567/* -------------------------------------------------------------------- */
2572{
2573 GHOST_SwapWindowBuffers(static_cast<GHOST_WindowHandle>(win->ghostwin));
2574}
2575
2577{
2578 GHOST_SetSwapInterval(static_cast<GHOST_WindowHandle>(win->ghostwin), interval);
2579}
2580
2581bool wm_window_get_swap_interval(wmWindow *win, int *r_interval)
2582{
2583 return GHOST_GetSwapInterval(static_cast<GHOST_WindowHandle>(win->ghostwin), r_interval);
2584}
2585
2588/* -------------------------------------------------------------------- */
2593 const int event_xy[2],
2594 int r_event_xy_other[2])
2595{
2596 int temp_xy[2];
2597 copy_v2_v2_int(temp_xy, event_xy);
2598 wm_cursor_position_to_ghost_screen_coords(win, &temp_xy[0], &temp_xy[1]);
2599
2600 GHOST_WindowHandle ghostwin = GHOST_GetWindowUnderCursor(g_system, temp_xy[0], temp_xy[1]);
2601
2602 if (!ghostwin) {
2603 return nullptr;
2604 }
2605
2606 wmWindow *win_other = static_cast<wmWindow *>(GHOST_GetWindowUserData(ghostwin));
2607 wm_cursor_position_from_ghost_screen_coords(win_other, &temp_xy[0], &temp_xy[1]);
2608 copy_v2_v2_int(r_event_xy_other, temp_xy);
2609 return win_other;
2610}
2611
2613{
2614 LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
2616 if (BLI_findindex(&sc->areabase, area) != -1) {
2617 return win;
2618 }
2619 }
2620 return nullptr;
2621}
2622
2625/* -------------------------------------------------------------------- */
2629void WM_init_state_size_set(int stax, int stay, int sizx, int sizy)
2630{
2631 wm_init_state.start = blender::int2(stax, stay); /* Left hand bottom position. */
2632 wm_init_state.size = blender::int2(std::max(sizx, 640), std::max(sizy, 480));
2634}
2635
2641
2647
2653
2655{
2657}
2658
2660{
2662}
2663
2666/* -------------------------------------------------------------------- */
2671{
2672 if (UNLIKELY(!g_system)) {
2673 return;
2674 }
2675
2677
2678 switch (U.tablet_api) {
2679 case USER_TABLET_NATIVE:
2681 break;
2682 case USER_TABLET_WINTAB:
2684 break;
2686 default:
2688 break;
2689 }
2690}
2691
2692void WM_cursor_warp(wmWindow *win, int x, int y)
2693{
2694 /* This function requires access to the GHOST_SystemHandle (`g_system`). */
2695
2696 if (!(win && win->ghostwin)) {
2697 return;
2698 }
2699
2700 int oldx = x, oldy = y;
2701
2703 GHOST_SetCursorPosition(g_system, static_cast<GHOST_WindowHandle>(win->ghostwin), x, y);
2704
2705 win->eventstate->prev_xy[0] = oldx;
2706 win->eventstate->prev_xy[1] = oldy;
2707
2708 win->eventstate->xy[0] = oldx;
2709 win->eventstate->xy[1] = oldy;
2710}
2711
2714/* -------------------------------------------------------------------- */
2719{
2720 const float fac = GHOST_GetNativePixelSize(static_cast<GHOST_WindowHandle>(win->ghostwin));
2721
2722 return int(fac * float(win->sizex));
2723}
2725{
2726 const float fac = GHOST_GetNativePixelSize(static_cast<GHOST_WindowHandle>(win->ghostwin));
2727
2728 return int(fac * float(win->sizey));
2729}
2730
2732{
2733 const float fac = GHOST_GetNativePixelSize(static_cast<GHOST_WindowHandle>(win->ghostwin));
2734
2735 return blender::int2(int(fac * float(win->sizex)), int(fac * float(win->sizey)));
2736}
2737
2738void WM_window_native_pixel_coords(const wmWindow *win, int *x, int *y)
2739{
2740 const float fac = GHOST_GetNativePixelSize(static_cast<GHOST_WindowHandle>(win->ghostwin));
2741
2742 *x *= fac;
2743 *y *= fac;
2744}
2745
2746void WM_window_rect_calc(const wmWindow *win, rcti *r_rect)
2747{
2748 const blender::int2 win_size = WM_window_native_pixel_size(win);
2749 BLI_rcti_init(r_rect, 0, win_size[0], 0, win_size[1]);
2750}
2752{
2753 rcti window_rect, screen_rect;
2754
2755 WM_window_rect_calc(win, &window_rect);
2756 screen_rect = window_rect;
2757
2758 /* Subtract global areas from screen rectangle. */
2759 LISTBASE_FOREACH (ScrArea *, global_area, &win->global_areas.areabase) {
2760 int height = ED_area_global_size_y(global_area) - 1;
2761
2762 if (global_area->global->flag & GLOBAL_AREA_IS_HIDDEN) {
2763 continue;
2764 }
2765
2766 switch (global_area->global->align) {
2768 screen_rect.ymax -= height;
2769 break;
2771 screen_rect.ymin += height;
2772 break;
2773 default:
2775 break;
2776 }
2777 }
2778
2779 BLI_assert(BLI_rcti_is_valid(&screen_rect));
2780
2781 *r_rect = screen_rect;
2782}
2783
2785{
2787}
2788
2790{
2792}
2793
2796/* -------------------------------------------------------------------- */
2800void WM_windows_scene_data_sync(const ListBase *win_lb, Scene *scene)
2801{
2802 LISTBASE_FOREACH (wmWindow *, win, win_lb) {
2803 if (WM_window_get_active_scene(win) == scene) {
2804 ED_workspace_scene_data_sync(win->workspace_hook, scene);
2805 }
2806 }
2807}
2808
2810{
2811 LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
2812 if (WM_window_get_active_screen(win) == screen) {
2813 return WM_window_get_active_scene(win);
2814 }
2815 }
2816
2817 return nullptr;
2818}
2819
2821{
2822 LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
2823 if (WM_window_get_active_screen(win) == screen) {
2825 }
2826 }
2827
2828 return nullptr;
2829}
2830
2832{
2833 LISTBASE_FOREACH (wmWindow *, win, &wm->windows) {
2834 if (WM_window_get_active_screen(win) == screen) {
2836 }
2837 }
2838 return nullptr;
2839}
2840
2842{
2843 return win->scene;
2844}
2845
2847{
2849 wmWindow *win_parent = (win->parent) ? win->parent : win;
2850 bool changed = false;
2851
2852 /* Set scene in parent and its child windows. */
2853 if (win_parent->scene != scene) {
2854 ED_screen_scene_change(C, win_parent, scene, true);
2855 changed = true;
2856 }
2857
2858 LISTBASE_FOREACH (wmWindow *, win_child, &wm->windows) {
2859 if (win_child->parent == win_parent && win_child->scene != scene) {
2860 ED_screen_scene_change(C, win_child, scene, true);
2861 changed = true;
2862 }
2863 }
2864
2865 if (changed) {
2866 /* Update depsgraph and renderers for scene change. */
2867 ViewLayer *view_layer = WM_window_get_active_view_layer(win_parent);
2868 ED_scene_change_update(bmain, scene, view_layer);
2869
2870 /* Complete redraw. */
2871 WM_event_add_notifier(C, NC_WINDOW, nullptr);
2872 }
2873}
2874
2876{
2877 Scene *scene = WM_window_get_active_scene(win);
2878 if (scene == nullptr) {
2879 return nullptr;
2880 }
2881
2882 ViewLayer *view_layer = BKE_view_layer_find(scene, win->view_layer_name);
2883 if (view_layer) {
2884 return view_layer;
2885 }
2886
2887 view_layer = BKE_view_layer_default_view(scene);
2888 if (view_layer) {
2889 WM_window_set_active_view_layer((wmWindow *)win, view_layer);
2890 }
2891
2892 return view_layer;
2893}
2894
2896{
2897 BLI_assert(BKE_view_layer_find(WM_window_get_active_scene(win), view_layer->name) != nullptr);
2898 Main *bmain = G_MAIN;
2899
2900 wmWindowManager *wm = static_cast<wmWindowManager *>(bmain->wm.first);
2901 wmWindow *win_parent = (win->parent) ? win->parent : win;
2902
2903 /* Set view layer in parent and child windows. */
2904 LISTBASE_FOREACH (wmWindow *, win_iter, &wm->windows) {
2905 if ((win_iter == win_parent) || (win_iter->parent == win_parent)) {
2906 STRNCPY(win_iter->view_layer_name, view_layer->name);
2907 bScreen *screen = BKE_workspace_active_screen_get(win_iter->workspace_hook);
2908 ED_render_view_layer_changed(bmain, screen);
2909 }
2910 }
2911}
2912
2914{
2915 /* Update layer name is correct after scene changes, load without UI, etc. */
2916 Scene *scene = WM_window_get_active_scene(win);
2917
2918 if (scene && BKE_view_layer_find(scene, win->view_layer_name) == nullptr) {
2919 ViewLayer *view_layer = BKE_view_layer_default_view(scene);
2920 STRNCPY(win->view_layer_name, view_layer->name);
2921 }
2922}
2923
2928
2930{
2932 wmWindow *win_parent = (win->parent) ? win->parent : win;
2933
2934 ED_workspace_change(workspace, C, wm, win);
2935
2936 LISTBASE_FOREACH (wmWindow *, win_child, &wm->windows) {
2937 if (win_child->parent == win_parent) {
2938 bScreen *screen = WM_window_get_active_screen(win_child);
2939 /* Don't change temporary screens, they only serve a single purpose. */
2940 if (screen->temp) {
2941 continue;
2942 }
2943 ED_workspace_change(workspace, C, wm, win_child);
2944 }
2945 }
2946}
2947
2949{
2950 const WorkSpace *workspace = WM_window_get_active_workspace(win);
2951 return (LIKELY(workspace != nullptr) ? BKE_workspace_active_layout_get(win->workspace_hook) :
2952 nullptr);
2953}
2955{
2956 BKE_workspace_active_layout_set(win->workspace_hook, win->winid, workspace, layout);
2957}
2958
2960{
2961 const WorkSpace *workspace = WM_window_get_active_workspace(win);
2962 /* May be null in rare cases like closing Blender. */
2963 return (LIKELY(workspace != nullptr) ? BKE_workspace_active_screen_get(win->workspace_hook) :
2964 nullptr);
2965}
2967{
2968 BKE_workspace_active_screen_set(win->workspace_hook, win->winid, workspace, screen);
2969}
2970
2972{
2973 const bScreen *screen = WM_window_get_active_screen(win);
2974 return (screen && screen->temp != 0);
2975}
2976
2979/* -------------------------------------------------------------------- */
2983#ifdef WITH_INPUT_IME
2984void wm_window_IME_begin(wmWindow *win, int x, int y, int w, int h, bool complete)
2985{
2986 /* NOTE: Keep in mind #wm_window_IME_begin is also used to reposition the IME window. */
2987
2988 BLI_assert(win);
2990 return;
2991 }
2992
2993 /* Convert to native OS window coordinates. */
2994 float fac = GHOST_GetNativePixelSize(static_cast<GHOST_WindowHandle>(win->ghostwin));
2995 x /= fac;
2996 y /= fac;
2998 static_cast<GHOST_WindowHandle>(win->ghostwin), x, win->sizey - y, w, h, complete);
2999}
3000
3001void wm_window_IME_end(wmWindow *win)
3002{
3004 return;
3005 }
3006
3007 BLI_assert(win);
3008 /* NOTE(@ideasman42): on WAYLAND a call to "begin" must be closed by an "end" call.
3009 * Even if no IME events were generated (which assigned `ime_data`).
3010 * TODO: check if #GHOST_EndIME can run on WIN32 & APPLE without causing problems. */
3011# if defined(WIN32) || defined(__APPLE__)
3012 BLI_assert(win->ime_data);
3013# endif
3014 GHOST_EndIME(static_cast<GHOST_WindowHandle>(win->ghostwin));
3015 win->ime_data = nullptr;
3016 win->ime_data_is_composing = false;
3017}
3018#endif /* WITH_INPUT_IME */
3019
3022/* -------------------------------------------------------------------- */
3027{
3028 /* On Windows there is a problem creating contexts that share resources (almost any object,
3029 * including legacy display lists, but also textures) with a context which is current in another
3030 * thread. This is a documented and behavior of both `::wglCreateContextAttribsARB()` and
3031 * `::wglShareLists()`.
3032 *
3033 * Other platforms might successfully share resources from context which is active somewhere
3034 * else, but to keep our code behave the same on all platform we expect contexts to only be
3035 * created from the main thread. */
3036
3039
3040 GHOST_GPUSettings gpuSettings = {0};
3041 const eGPUBackendType gpu_backend = GPU_backend_type_selection_get();
3042 gpuSettings.context_type = wm_ghost_drawing_context_type(gpu_backend);
3043 if (G.debug & G_DEBUG_GPU) {
3044 gpuSettings.flags |= GHOST_gpuDebugContext;
3045 }
3046 gpuSettings.preferred_device.index = U.gpu_preferred_index;
3047 gpuSettings.preferred_device.vendor_id = U.gpu_preferred_vendor_id;
3048 gpuSettings.preferred_device.device_id = U.gpu_preferred_device_id;
3049
3050 return GHOST_CreateGPUContext(g_system, gpuSettings);
3051}
3052
3054{
3056 GHOST_DisposeGPUContext(g_system, (GHOST_ContextHandle)context);
3057}
3058
3060{
3062 GHOST_ActivateGPUContext((GHOST_ContextHandle)context);
3063}
3064
3066{
3068 GHOST_ReleaseGPUContext((GHOST_ContextHandle)context);
3069}
3070
3071void WM_ghost_show_message_box(const char *title,
3072 const char *message,
3073 const char *help_label,
3074 const char *continue_label,
3075 const char *link,
3076 GHOST_DialogOptions dialog_options)
3077{
3079 GHOST_ShowMessageBox(g_system, title, message, help_label, continue_label, link, dialog_options);
3080}
3081
const char * BKE_blender_version_string(void)
Definition blender.cc:139
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:205
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:837
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition report.cc:125
void BKE_screen_area_map_free(ScrAreaMap *area_map) ATTR_NONNULL()
Definition screen.cc:623
ScrArea * BKE_screen_find_big_area(const bScreen *screen, int spacetype, short min)
Definition screen.cc:903
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:638
void BKE_workspace_active_screen_set(WorkSpaceInstanceHook *hook, int winid, WorkSpace *workspace, bScreen *screen) SETTER_ATTRS
Definition workspace.cc:617
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:604
bScreen * BKE_workspace_active_screen_get(const WorkSpaceInstanceHook *hook) GETTER_ATTRS
Definition workspace.cc:613
WorkSpace * BKE_workspace_active_get(WorkSpaceInstanceHook *hook) GETTER_ATTRS
Definition workspace.cc:562
void BKE_workspace_active_set(WorkSpaceInstanceHook *hook, WorkSpace *workspace) SETTER_ATTRS
Definition workspace.cc:566
WorkSpaceLayout * BKE_workspace_active_layout_get(const WorkSpaceInstanceHook *hook) GETTER_ATTRS
Definition workspace.cc:586
void BLF_cache_clear()
Definition blf.cc:99
#define BLI_assert_unreachable()
Definition BLI_assert.h:97
#define BLI_assert(a)
Definition BLI_assert.h:50
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:57
void BLI_kdtree_nd_ free(KDTree *tree)
BLI_INLINE bool BLI_listbase_is_empty(const struct ListBase *lb)
#define LISTBASE_FOREACH(type, var, list)
#define LISTBASE_FOREACH_MUTABLE(type, var, list)
void void BLI_INLINE bool BLI_listbase_is_single(const struct ListBase *lb)
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:110
void BLI_remlink(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:130
int BLI_findindex(const struct ListBase *listbase, const void *vlink) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
void * BLI_pophead(ListBase *listbase) ATTR_NONNULL(1)
Definition listbase.cc:251
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])
void void void const char * BLI_path_basename(const char *path) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT
const char * BLI_path_extension_or_end(const char *filepath) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL
BLI_INLINE int BLI_rcti_size_y(const struct rcti *rct)
Definition BLI_rect.h:193
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.c:418
void BLI_rcti_resize_y(struct rcti *rect, int y)
Definition rct.c:609
BLI_INLINE int BLI_rcti_size_x(const struct rcti *rct)
Definition BLI_rect.h:189
void BLI_rcti_resize_x(struct rcti *rect, int x)
Definition rct.c:603
char * BLI_strdup(const char *str) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC
Definition string.c:40
#define STRNCPY(dst, src)
Definition BLI_string.h:593
#define SNPRINTF(dst, format,...)
Definition BLI_string.h:597
int BLI_str_utf8_invalid_strip(char *str, size_t length) ATTR_NONNULL(1)
unsigned int uint
void BLI_system_backtrace(FILE *fp)
Definition system.c:63
int BLI_thread_is_main(void)
Definition threads.cc:179
Platform independent time functions.
void BLI_time_sleep_ms(int ms)
Definition time.c:85
double BLI_time_now_seconds(void)
Definition time.c: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)
typedef double(DMatrix)[4][4]
#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
@ GLOBAL_AREA_ALIGN_BOTTOM
@ GLOBAL_AREA_ALIGN_TOP
@ SPACE_EMPTY
#define SPACE_TYPE_ANY
@ USER_SAVE_PROMPT
@ USER_NO_MULTITOUCH_GESTURES
@ USER_TABLET_NATIVE
@ USER_TABLET_AUTOMATIC
@ USER_TABLET_WINTAB
@ VIRTUAL_PIXEL_NATIVE
@ VIRTUAL_PIXEL_DOUBLE
#define UI_SCALE_FAC
@ WM_INIT_FLAG_WINDOW
int ED_file_extension_icon(const char *path)
Definition filelist.cc:2862
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:2592
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:3677
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)
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)
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)
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)
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)
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:85
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:96
@ GHOST_kCapabilityWindowPosition
@ GHOST_kCapabilityGPUReadFrontBuffer
@ GHOST_kCapabilityCursorWarp
@ GHOST_kCapabilityInputIME
@ GHOST_kCapabilityTrackpadPhysicalDirection
@ GHOST_kCapabilityClipboardImages
@ GHOST_kCapabilityPrimaryClipboard
@ GHOST_kCapabilityDesktopSample
GHOST_TKey
@ GHOST_kKeyLeftOS
@ GHOST_kKeyLeftAlt
@ GHOST_kKeyRightShift
@ GHOST_kKeyRightOS
@ GHOST_kKeyLeftControl
@ GHOST_kKeyRightAlt
@ GHOST_kKeyRightControl
@ GHOST_kKeyUnknown
@ GHOST_kKeyLeftShift
const void * GHOST_TEventDataPtr
GHOST_TDrawingContextType
@ GHOST_kDrawingContextTypeNone
@ GHOST_kWindowOrderTop
@ GHOST_kWindowOrderBottom
GHOST_TModifierKey
@ GHOST_kModifierKeyRightControl
@ GHOST_kModifierKeyLeftControl
@ GHOST_kModifierKeyRightAlt
@ GHOST_kModifierKeyRightShift
@ GHOST_kModifierKeyLeftAlt
@ GHOST_kModifierKeyLeftShift
@ GHOST_kModifierKeyLeftOS
@ GHOST_kModifierKeyRightOS
@ GHOST_kFailure
Definition GHOST_Types.h:87
@ GHOST_kSuccess
Definition GHOST_Types.h:87
@ GHOST_gpuStereoVisual
Definition GHOST_Types.h:76
@ GHOST_gpuDebugContext
Definition GHOST_Types.h:77
void(* GHOST_TBacktraceFn)(void *file_handle)
Definition GHOST_Types.h:63
@ GHOST_kDragnDropTypeFilenames
@ GHOST_kDragnDropTypeString
@ GHOST_kTabletAutomatic
@ GHOST_kTabletWinPointer
@ GHOST_kTabletWintab
GHOST_DialogOptions
Definition GHOST_Types.h:80
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()
void imb_freerectImBuf(ImBuf *ibuf)
void IMB_rect_from_float(ImBuf *ibuf)
Definition divers.cc:694
Contains defines and structs used throughout the imbuf module.
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
@ UI_EMBOSS
void UI_block_theme_style_set(uiBlock *block, char theme_style)
uiLayout * uiItemsAlertBox(uiBlock *block, const uiStyle *style, const int dialog_width, const eAlertIcon icon, const int icon_size)
void uiItemL(uiLayout *layout, const char *name, int icon)
void UI_popup_block_invoke(bContext *C, uiBlockCreateFunc func, void *arg, uiFreeArgFunc arg_free)
uiBlock * UI_block_begin(const bContext *C, ARegion *region, std::string name, eUIEmbossType emboss)
void uiItemS(uiLayout *layout)
void UI_block_emboss_set(uiBlock *block, eUIEmbossType emboss)
@ UI_BLOCK_THEME_STYLE_POPUP
void UI_block_bounds_set_centered(uiBlock *block, int addval)
Definition interface.cc:616
uiLayout * uiLayoutColumn(uiLayout *layout, bool align)
uiBut * uiItemL_ex(uiLayout *layout, const char *name, int icon, bool highlight, bool redalert)
void UI_popup_handlers_remove_all(bContext *C, ListBase *handlers)
@ ALERT_ICON_ERROR
eWindowAlignment
Definition WM_api.hh:338
@ WIN_ALIGN_LOCATION_CENTER
Definition WM_api.hh:340
@ WIN_ALIGN_PARENT_CENTER
Definition WM_api.hh:341
eWM_CapabilitiesFlag
Definition WM_api.hh:167
@ WM_CAPABILITY_PRIMARY_CLIPBOARD
Definition WM_api.hh:176
@ WM_CAPABILITY_WINDOW_POSITION
Definition WM_api.hh:171
@ WM_CAPABILITY_CURSOR_WARP
Definition WM_api.hh:169
@ WM_CAPABILITY_INITIALIZED
Definition WM_api.hh:190
@ WM_CAPABILITY_TRACKPAD_PHYSICAL_DIRECTION
Definition WM_api.hh:188
@ WM_CAPABILITY_GPU_FRONT_BUFFER_READ
Definition WM_api.hh:180
@ WM_CAPABILITY_CLIPBOARD_IMAGES
Definition WM_api.hh:182
@ WM_CAPABILITY_DESKTOP_SAMPLE
Definition WM_api.hh:184
@ WM_CAPABILITY_INPUT_IME
Definition WM_api.hh:186
#define NC_WINDOW
Definition WM_types.hh:342
eWM_EventFlag
Definition WM_types.hh:637
@ WM_DRAG_NOP
Definition WM_types.hh:1180
@ WM_DRAG_FREE_DATA
Definition WM_types.hh:1181
@ KM_NOTHING
Definition WM_types.hh:283
@ KM_RELEASE
Definition WM_types.hh:285
CLG_LogRef * WM_LOG_EVENTS
#define NC_SCREEN
Definition WM_types.hh:344
#define NA_ADDED
Definition WM_types.hh:552
#define NA_EDITED
Definition WM_types.hh:550
#define NA_REMOVED
Definition WM_types.hh:553
@ WM_OP_INVOKE_DEFAULT
Definition WM_types.hh:218
@ WM_DRAG_PATH
Definition WM_types.hh:1160
@ WM_DRAG_STRING
Definition WM_types.hh:1169
@ KM_CTRL
Definition WM_types.hh:256
@ KM_ALT
Definition WM_types.hh:257
@ KM_OSKEY
Definition WM_types.hh:259
@ KM_SHIFT
Definition WM_types.hh:255
@ WM_TIMER_TAGGED_FOR_REMOVAL
Definition WM_types.hh:905
@ WM_TIMER_NO_FREE_CUSTOM_DATA
Definition WM_types.hh:900
#define ND_LAYOUTDELETE
Definition WM_types.hh:390
struct GPUContext GPUContext
ATTR_WARN_UNUSED_RESULT const BMLoop * l
void activate(bool forceActivation=false) const
unsigned int U
Definition btGjkEpa3.h:78
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition btQuadWord.h:119
local_group_size(16, 16) .push_constant(Type b
#define printf
double time
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
#define str(s)
uint col
struct ImBuf * IMB_allocFromBuffer(const uint8_t *, const float *, unsigned int, unsigned int, unsigned int)
#define PRIu64
Definition inttypes.h:132
void *(* MEM_mallocN)(size_t len, const char *str)
Definition mallocn.cc:44
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
void *(* MEM_callocN)(size_t len, const char *str)
Definition mallocn.cc:42
ccl_device_inline float3 ceil(const float3 a)
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)
unsigned int uint32_t
Definition stdint.h:80
unsigned char uint8_t
Definition stdint.h:78
unsigned __int64 uint64_t
Definition stdint.h:90
GHOST_TDrawingContextType context_type
GHOST_GPUDevice preferred_device
GHOST_TDragnDropTypes dataType
GHOST_TDragnDropDataPtr data
ImBufByteBuffer byte_buffer
void * first
ListBase wm
Definition BKE_main.hh:239
ListBase areabase
char name[64]
GHOST_TWindowState windowstate
Definition wm_window.cc:126
blender::int2 size
Definition wm_window.cc:123
blender::int2 start
Definition wm_window.cc:124
eWinOverrideFlag override_flag
Definition wm_window.cc:127
bool window_focus
Definition wm_window.cc:129
bool native_pixels
Definition wm_window.cc:130
Wrapper for bScreen.
ListBase areabase
int ymin
int ymax
int xmin
int xmax
int xy[2]
Definition WM_types.hh:726
int prev_xy[2]
Definition WM_types.hh:785
short keymodifier
Definition WM_types.hh:748
uint8_t modifier
Definition WM_types.hh:739
wmGenericCallbackFn exec
Definition WM_types.hh:150
struct ReportList * reports
int event_type
Definition WM_types.hh:918
wmTimerFlags flags
Definition WM_types.hh:920
bool sleep
Definition WM_types.hh:936
double time_next
Definition WM_types.hh:932
void * customdata
Definition WM_types.hh:922
wmWindow * win
Definition WM_types.hh:913
double time_start
Definition WM_types.hh:934
double time_step
Definition WM_types.hh:916
double time_last
Definition WM_types.hh:930
struct wmKeyConfig * defaultconf
WindowManagerRuntimeHandle * runtime
struct wmWindow * winactive
struct wmWindow * windrawable
struct wmWindow * parent
struct wmEvent * eventstate
struct wmEvent * event_last_handled
struct Scene * scene
const struct wmIMEData * ime_data
struct wmEvent_ConsecutiveData * event_queue_consecutive_gesture_data
struct wmWindow * next
ScrAreaMap global_areas
struct WorkSpaceInstanceHook * workspace_hook
struct Stereo3dFormat * stereo3d_format
wmTimer * timer
void WM_check(bContext *C)
Definition wm.cc:479
@ 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:170
int winid
Definition wm_draw.cc:169
void wm_draw_update(bContext *C)
Definition wm_draw.cc:1541
wmEvent * wm_event_add(wmWindow *win, const wmEvent *event_to_add)
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)
int WM_operator_name_call_ptr(bContext *C, wmOperatorType *ot, wmOperatorCallContext context, PointerRNA *properties, const wmEvent *event)
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
#define ISTIMER(event_type)
@ TIMERNOTIFIER
@ TIMERJOBS
@ TIMERAUTOSAVE
@ EVENT_NONE
@ MOUSEMOVE
@ EVT_DROP
bool wm_file_or_session_data_has_unsaved_changes(const Main *bmain, const wmWindowManager *wm)
Definition wm_files.cc:181
void wm_autosave_timer(Main *bmain, wmWindowManager *wm, wmTimer *)
Definition wm_files.cc:2358
wmOperatorType * ot
Definition wm_files.cc:4125
void wm_close_file_dialog(bContext *C, wmGenericCallback *post_action)
Definition wm_files.cc:4752
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:648
void wm_jobs_timer(wmWindowManager *wm, wmTimer *wt)
Definition wm_jobs.cc:656
wmKeyMap * WM_keymap_ensure(wmKeyConfig *keyconf, const char *idname, int spaceid, int regionid)
Definition wm_keymap.cc:897
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 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:100
@ WIN_OVERRIDE_WINSTATE
Definition wm_window.cc:102
@ WIN_OVERRIDE_GEOM
Definition wm_window.cc:101
wmWindow * wm_window_copy(Main *bmain, wmWindowManager *wm, wmWindow *win_src, const bool duplicate_layout, const bool child)
Definition wm_window.cc:324
int wm_window_new_main_exec(bContext *C, wmOperator *op)
static void wm_window_ghostwindow_ensure(wmWindowManager *wm, wmWindow *win, bool is_dialog)
Definition wm_window.cc:818
ModSide
Definition wm_window.cc:156
@ MOD_SIDE_RIGHT
Definition wm_window.cc:158
@ MOD_SIDE_LEFT
Definition wm_window.cc:157
void WM_window_set_active_scene(Main *bmain, bContext *C, wmWindow *win, Scene *scene)
void wm_cursor_position_from_ghost_screen_coords(wmWindow *win, int *x, int *y)
GHOST_TKey ghost_key_pair[2]
Definition wm_window.cc:139
static GHOST_SystemHandle g_system
Definition wm_window.cc:95
int wm_window_close_exec(bContext *C, wmOperator *)
wmWindow * wm_window_new(const Main *bmain, wmWindowManager *wm, wmWindow *parent, bool dialog)
Definition wm_window.cc:308
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:194
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:106
void WM_init_state_maximized_set()
void WM_window_set_active_workspace(bContext *C, wmWindow *win, WorkSpace *workspace)
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:140
static struct WMInitStruct wm_init_state
static void wm_window_ensure_eventstate(wmWindow *win)
Definition wm_window.cc:709
int wm_window_fullscreen_toggle_exec(bContext *C, wmOperator *)
void wm_quit_with_optional_confirmation_prompt(bContext *C, wmWindow *win)
Definition wm_window.cc:397
void * WM_system_gpu_context_create()
static uint8_t wm_ghost_modifier_query(const enum ModSide side)
bool WM_clipboard_image_set(ImBuf *ibuf)
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:171
static void wm_window_ghostwindow_add(wmWindowManager *wm, const char *title, wmWindow *win, bool is_dialog)
Definition wm_window.cc:722
void wm_window_events_process(const bContext *C)
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:207
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:429
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:608
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:389
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:552
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)
Definition wm_window.cc:905
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)
Definition wm_window.cc:950
void WM_system_gpu_context_activate(void *context)
void WM_event_timer_remove_notifier(wmWindowManager *wm, wmWindow *win, wmTimer *timer)
void wm_window_clear_drawable(wmWindowManager *wm)
static uiBlock * block_create_gpu_backend_fallback(bContext *C, ARegion *region, void *)
static int find_free_winid(wmWindowManager *wm)
Definition wm_window.cc:296
static const struct @1388 g_modifier_table[]
void WM_progress_clear(wmWindow *win)
void WM_init_state_size_set(int stax, int stay, int sizx, int sizy)
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:354
static bool wm_window_update_size_position(wmWindow *win)
Definition wm_window.cc:917
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)
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:700
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:380
struct @1389 * g_wm_clipboard_text_simulate
static const char * g_system_backend_id
Definition wm_window.cc:97
static void wm_window_update_eventstate_modifiers_clear(wmWindowManager *wm, wmWindow *win, const uint64_t event_time_ms)
Definition wm_window.cc:663
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:235
int wm_window_new_exec(bContext *C, wmOperator *op)
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:485
void wm_ghost_init(bContext *C)
GHOST_TDrawingContextType wm_ghost_drawing_context_type(const eGPUBackendType gpu_backend)
void WM_windows_scene_data_sync(const ListBase *win_lb, Scene *scene)
void wm_window_ghostwindows_ensure(wmWindowManager *wm)
Definition wm_window.cc:880
void WM_init_window_focus_set(bool do_it)
WorkSpace * WM_window_get_active_workspace(const wmWindow *win)
bool wm_get_desktopsize(int r_size[2])
Definition wm_window.cc:182
void wm_window_timers_delete_removed(wmWindowManager *wm)
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)
wmTimer * WM_event_timer_add(wmWindowManager *wm, wmWindow *win, const int event_type, const double time_step)
void WM_system_gpu_context_release(void *context)
bScreen * WM_window_get_active_screen(const wmWindow *win)
uint8_t flag
Definition wm_window.cc:138
bool wm_xr_events_handle(wmWindowManager *wm)
Definition wm_xr.cc:127