Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/windowmanager/intern')
-rw-r--r--source/blender/windowmanager/intern/wm.c170
-rw-r--r--source/blender/windowmanager/intern/wm_cursors.c18
-rw-r--r--source/blender/windowmanager/intern/wm_dragdrop.c18
-rw-r--r--source/blender/windowmanager/intern/wm_draw.c1115
-rw-r--r--source/blender/windowmanager/intern/wm_event_system.c959
-rw-r--r--source/blender/windowmanager/intern/wm_files.c324
-rw-r--r--source/blender/windowmanager/intern/wm_files_link.c105
-rw-r--r--source/blender/windowmanager/intern/wm_gesture.c285
-rw-r--r--source/blender/windowmanager/intern/wm_gesture_ops.c52
-rw-r--r--source/blender/windowmanager/intern/wm_init_exit.c215
-rw-r--r--source/blender/windowmanager/intern/wm_keymap.c51
-rw-r--r--source/blender/windowmanager/intern/wm_operator_props.c4
-rw-r--r--source/blender/windowmanager/intern/wm_operator_type.c95
-rw-r--r--source/blender/windowmanager/intern/wm_operators.c469
-rw-r--r--source/blender/windowmanager/intern/wm_playanim.c102
-rw-r--r--source/blender/windowmanager/intern/wm_stereo.c327
-rw-r--r--source/blender/windowmanager/intern/wm_subwindow.c348
-rw-r--r--source/blender/windowmanager/intern/wm_toolsystem.c602
-rw-r--r--source/blender/windowmanager/intern/wm_tooltip.c12
-rw-r--r--source/blender/windowmanager/intern/wm_window.c606
20 files changed, 3822 insertions, 2055 deletions
diff --git a/source/blender/windowmanager/intern/wm.c b/source/blender/windowmanager/intern/wm.c
index 132789aade4..9e7136dc81d 100644
--- a/source/blender/windowmanager/intern/wm.c
+++ b/source/blender/windowmanager/intern/wm.c
@@ -52,9 +52,11 @@
#include "BKE_screen.h"
#include "BKE_report.h"
#include "BKE_global.h"
+#include "BKE_workspace.h"
#include "WM_api.h"
#include "WM_types.h"
+#include "WM_message.h"
#include "wm_window.h"
#include "wm_event_system.h"
#include "wm_draw.h"
@@ -222,6 +224,138 @@ void WM_operator_handlers_clear(wmWindowManager *wm, wmOperatorType *ot)
}
/* ************ uiListType handling ************** */
+
+static GHash *uilisttypes_hash = NULL;
+
+uiListType *WM_uilisttype_find(const char *idname, bool quiet)
+{
+ uiListType *ult;
+
+ if (idname[0]) {
+ ult = BLI_ghash_lookup(uilisttypes_hash, idname);
+ if (ult) {
+ return ult;
+ }
+ }
+
+ if (!quiet) {
+ printf("search for unknown uilisttype %s\n", idname);
+ }
+
+ return NULL;
+}
+
+bool WM_uilisttype_add(uiListType *ult)
+{
+ BLI_ghash_insert(uilisttypes_hash, ult->idname, ult);
+ return 1;
+}
+
+void WM_uilisttype_freelink(uiListType *ult)
+{
+ bool ok;
+
+ ok = BLI_ghash_remove(uilisttypes_hash, ult->idname, NULL, MEM_freeN);
+
+ BLI_assert(ok);
+ (void)ok;
+}
+
+/* called on initialize WM_init() */
+void WM_uilisttype_init(void)
+{
+ uilisttypes_hash = BLI_ghash_str_new_ex("uilisttypes_hash gh", 16);
+}
+
+void WM_uilisttype_free(void)
+{
+ GHashIterator gh_iter;
+
+ GHASH_ITER (gh_iter, uilisttypes_hash) {
+ uiListType *ult = BLI_ghashIterator_getValue(&gh_iter);
+ if (ult->ext.free) {
+ ult->ext.free(ult->ext.data);
+ }
+ }
+
+ BLI_ghash_free(uilisttypes_hash, NULL, MEM_freeN);
+ uilisttypes_hash = NULL;
+}
+
+/* ************ MenuType handling ************** */
+
+static GHash *menutypes_hash = NULL;
+
+MenuType *WM_menutype_find(const char *idname, bool quiet)
+{
+ MenuType *mt;
+
+ if (idname[0]) {
+ mt = BLI_ghash_lookup(menutypes_hash, idname);
+ if (mt)
+ return mt;
+ }
+
+ if (!quiet)
+ printf("search for unknown menutype %s\n", idname);
+
+ return NULL;
+}
+
+bool WM_menutype_add(MenuType *mt)
+{
+ BLI_ghash_insert(menutypes_hash, mt->idname, mt);
+ return true;
+}
+
+void WM_menutype_freelink(MenuType *mt)
+{
+ bool ok;
+
+ ok = BLI_ghash_remove(menutypes_hash, mt->idname, NULL, MEM_freeN);
+
+ BLI_assert(ok);
+ (void)ok;
+}
+
+/* called on initialize WM_init() */
+void WM_menutype_init(void)
+{
+ /* reserve size is set based on blender default setup */
+ menutypes_hash = BLI_ghash_str_new_ex("menutypes_hash gh", 512);
+}
+
+void WM_menutype_free(void)
+{
+ GHashIterator gh_iter;
+
+ GHASH_ITER (gh_iter, menutypes_hash) {
+ MenuType *mt = BLI_ghashIterator_getValue(&gh_iter);
+ if (mt->ext.free) {
+ mt->ext.free(mt->ext.data);
+ }
+ }
+
+ BLI_ghash_free(menutypes_hash, NULL, MEM_freeN);
+ menutypes_hash = NULL;
+}
+
+bool WM_menutype_poll(bContext *C, MenuType *mt)
+{
+ /* If we're tagged, only use compatible. */
+ if (mt->owner_id[0] != '\0') {
+ const WorkSpace *workspace = CTX_wm_workspace(C);
+ if (BKE_workspace_owner_id_check(workspace, mt->owner_id) == false) {
+ return false;
+ }
+ }
+
+ if (mt->poll != NULL) {
+ return mt->poll(C, mt);
+ }
+ return true;
+}
+
/* ****************************************** */
void WM_keymap_init(bContext *C)
@@ -238,7 +372,7 @@ void WM_keymap_init(bContext *C)
/* initialize only after python init is done, for keymaps that
* use python operators */
- if (CTX_py_init_get(C) && (wm->initialized & WM_INIT_KEYMAP) == 0) {
+ if (CTX_py_init_get(C) && (wm->initialized & WM_KEYMAP_IS_INITIALIZED) == 0) {
/* create default key config, only initialize once,
* it's persistent across sessions */
if (!(wm->defaultconf->flag & KEYCONF_INIT_DEFAULT)) {
@@ -251,7 +385,7 @@ void WM_keymap_init(bContext *C)
WM_keyconfig_update_tag(NULL, NULL);
WM_keyconfig_update(wm);
- wm->initialized |= WM_INIT_KEYMAP;
+ wm->initialized |= WM_KEYMAP_IS_INITIALIZED;
}
}
@@ -272,7 +406,7 @@ void WM_check(bContext *C)
if (!G.background) {
/* case: fileread */
- if ((wm->initialized & WM_INIT_WINDOW) == 0) {
+ if ((wm->initialized & WM_WINDOW_IS_INITIALIZED) == 0) {
WM_keymap_init(C);
WM_autosave_init(wm);
}
@@ -281,11 +415,15 @@ void WM_check(bContext *C)
wm_window_ghostwindows_ensure(wm);
}
+ if (wm->message_bus == NULL) {
+ wm->message_bus = WM_msgbus_create();
+ }
+
/* case: fileread */
/* note: this runs in bg mode to set the screen context cb */
- if ((wm->initialized & WM_INIT_WINDOW) == 0) {
+ if ((wm->initialized & WM_WINDOW_IS_INITIALIZED) == 0) {
ED_screens_initialize(bmain, wm);
- wm->initialized |= WM_INIT_WINDOW;
+ wm->initialized |= WM_WINDOW_IS_INITIALIZED;
}
}
@@ -314,17 +452,21 @@ void wm_clear_default_size(bContext *C)
}
/* on startup, it adds all data, for matching */
-void wm_add_default(bContext *C)
+void wm_add_default(Main *bmain, bContext *C)
{
- wmWindowManager *wm = BKE_libblock_alloc(CTX_data_main(C), ID_WM, "WinMan", 0);
+ wmWindowManager *wm = BKE_libblock_alloc(bmain, ID_WM, "WinMan", 0);
wmWindow *win;
bScreen *screen = CTX_wm_screen(C); /* XXX from file read hrmf */
+ WorkSpace *workspace;
+ WorkSpaceLayout *layout = BKE_workspace_layout_find_global(bmain, screen, &workspace);
CTX_wm_manager_set(C, wm);
- win = wm_window_new(C);
- win->screen = screen;
+ win = wm_window_new(C, NULL);
+ win->scene = CTX_data_scene(C);
+ STRNCPY(win->view_layer_name, CTX_data_view_layer(C)->name);
+ BKE_workspace_active_set(win->workspace_hook, workspace);
+ BKE_workspace_hook_layout_for_workspace_set(win->workspace_hook, workspace, layout);
screen->winid = win->winid;
- BLI_strncpy(win->screenname, screen->id.name + 2, sizeof(win->screenname));
wm->winactive = win;
wm->file_saved = 1;
@@ -343,8 +485,8 @@ void wm_close_and_free(bContext *C, wmWindowManager *wm)
wm_autosave_timer_ended(wm);
while ((win = BLI_pophead(&wm->windows))) {
- win->screen = NULL; /* prevent draw clear to use screen */
- wm_draw_window_clear(win);
+ /* prevent draw clear to use screen */
+ BKE_workspace_active_set(win->workspace_hook, NULL);
wm_window_free(C, wm, win);
}
@@ -358,6 +500,10 @@ void wm_close_and_free(bContext *C, wmWindowManager *wm)
BLI_freelistN(&wm->queue);
+ if (wm->message_bus != NULL) {
+ WM_msgbus_destroy(wm->message_bus);
+ }
+
BLI_freelistN(&wm->paintcursors);
WM_drag_free_list(&wm->drags);
diff --git a/source/blender/windowmanager/intern/wm_cursors.c b/source/blender/windowmanager/intern/wm_cursors.c
index 24ec3aef759..eaeaac45f89 100644
--- a/source/blender/windowmanager/intern/wm_cursors.c
+++ b/source/blender/windowmanager/intern/wm_cursors.c
@@ -42,6 +42,7 @@
#include "DNA_listBase.h"
#include "DNA_userdef_types.h"
+#include "DNA_workspace_types.h"
#include "BKE_context.h"
#include "BKE_global.h"
@@ -156,6 +157,23 @@ void WM_cursor_set(wmWindow *win, int curs)
}
}
+bool WM_cursor_set_from_tool(struct wmWindow *win, const ScrArea *sa, const ARegion *ar)
+{
+ if (ar && (ar->regiontype != RGN_TYPE_WINDOW)) {
+ return false;
+ }
+
+ bToolRef_Runtime *tref_rt = (sa && sa->runtime.tool) ? sa->runtime.tool->runtime : NULL;
+ if (tref_rt && tref_rt->cursor != CURSOR_STD) {
+ if (win->modalcursor == 0) {
+ WM_cursor_set(win, tref_rt->cursor);
+ win->cursor = tref_rt->cursor;
+ return true;
+ }
+ }
+ return false;
+}
+
void WM_cursor_modal_set(wmWindow *win, int val)
{
if (win->lastcursor == 0)
diff --git a/source/blender/windowmanager/intern/wm_dragdrop.c b/source/blender/windowmanager/intern/wm_dragdrop.c
index 8bb4bf4f304..eca3a838c0f 100644
--- a/source/blender/windowmanager/intern/wm_dragdrop.c
+++ b/source/blender/windowmanager/intern/wm_dragdrop.c
@@ -46,6 +46,8 @@
#include "BKE_context.h"
+#include "GPU_shader.h"
+
#include "IMB_imbuf_types.h"
#include "UI_interface.h"
@@ -269,10 +271,10 @@ void wm_drags_check_ops(bContext *C, const wmEvent *event)
static void wm_drop_operator_draw(const char *name, int x, int y)
{
const uiFontStyle *fstyle = UI_FSTYLE_WIDGET;
- const unsigned char fg[4] = {255, 255, 255, 255};
- const unsigned char bg[4] = {0, 0, 0, 50};
+ const float col_fg[4] = {1.0f, 1.0f, 1.0f, 1.0f};
+ const float col_bg[4] = {0.0f, 0.0f, 0.0f, 0.2f};
- UI_fontstyle_draw_simple_backdrop(fstyle, x, y, name, fg, bg);
+ UI_fontstyle_draw_simple_backdrop(fstyle, x, y, name, col_fg, col_bg);
}
static const char *wm_drag_name(wmDrag *drag)
@@ -333,8 +335,10 @@ void wm_drags_draw(bContext *C, wmWindow *win, rcti *rect)
if (rect)
drag_rect_minmax(rect, x, y, x + drag->sx, y + drag->sy);
else {
- glColor4f(1.0, 1.0, 1.0, 0.65); /* this blends texture */
- glaDrawPixelsTexScaled(x, y, drag->imb->x, drag->imb->y, GL_RGBA, GL_UNSIGNED_BYTE, GL_NEAREST, drag->imb->rect, drag->scale, drag->scale);
+ float col[4] = {1.0f, 1.0f, 1.0f, 0.65f}; /* this blends texture */
+ IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_COLOR);
+ immDrawPixelsTexScaled(&state, x, y, drag->imb->x, drag->imb->y, GL_RGBA, GL_UNSIGNED_BYTE, GL_NEAREST,
+ drag->imb->rect, drag->scale, drag->scale, 1.0f, 1.0f, col);
}
}
else {
@@ -362,8 +366,8 @@ void wm_drags_draw(bContext *C, wmWindow *win, rcti *rect)
drag_rect_minmax(rect, x, y, x + w, y + iconsize);
}
else {
- glColor4ub(255, 255, 255, 255);
- UI_fontstyle_draw_simple(fstyle, x, y, wm_drag_name(drag));
+ const unsigned char col[] = {255, 255, 255, 255};
+ UI_fontstyle_draw_simple(fstyle, x, y, wm_drag_name(drag), col);
}
/* operator name with roundbox */
diff --git a/source/blender/windowmanager/intern/wm_draw.c b/source/blender/windowmanager/intern/wm_draw.c
index d18337ee80c..5314c434c4c 100644
--- a/source/blender/windowmanager/intern/wm_draw.c
+++ b/source/blender/windowmanager/intern/wm_draw.c
@@ -34,6 +34,8 @@
#include <string.h>
#include "DNA_listBase.h"
+#include "DNA_object_types.h"
+#include "DNA_camera_types.h"
#include "DNA_screen_types.h"
#include "DNA_windowmanager_types.h"
#include "DNA_userdef_types.h"
@@ -49,6 +51,9 @@
#include "BKE_context.h"
#include "BKE_image.h"
#include "BKE_main.h"
+#include "BKE_screen.h"
+#include "BKE_scene.h"
+#include "BKE_workspace.h"
#include "GHOST_C-api.h"
@@ -58,8 +63,11 @@
#include "GPU_draw.h"
#include "GPU_extensions.h"
-#include "GPU_glew.h"
-#include "GPU_basic_shader.h"
+#include "GPU_framebuffer.h"
+#include "GPU_immediate.h"
+#include "GPU_matrix.h"
+#include "GPU_texture.h"
+#include "GPU_viewport.h"
#include "RE_engine.h"
@@ -74,87 +82,131 @@
# include "BKE_subsurf.h"
#endif
-/* swap */
-#define WIN_NONE_OK 0
-#define WIN_BACK_OK 1
-#define WIN_FRONT_OK 2
-#define WIN_BOTH_OK 3
-
-/* ******************* drawing, overlays *************** */
+/* ******************* paint cursor *************** */
static void wm_paintcursor_draw(bContext *C, ARegion *ar)
{
wmWindowManager *wm = CTX_wm_manager(C);
-
- if (wm->paintcursors.first) {
- wmWindow *win = CTX_wm_window(C);
- bScreen *screen = win->screen;
- wmPaintCursor *pc;
-
- if (ar->swinid && screen->subwinactive == ar->swinid) {
- for (pc = wm->paintcursors.first; pc; pc = pc->next) {
- if (pc->poll == NULL || pc->poll(C)) {
- ARegion *ar_other = CTX_wm_region(C);
- if (ELEM(win->grabcursor, GHOST_kGrabWrap, GHOST_kGrabHide)) {
- int x = 0, y = 0;
- wm_get_cursor_position(win, &x, &y);
- pc->draw(C,
- x - ar_other->winrct.xmin,
- y - ar_other->winrct.ymin,
- pc->customdata);
- }
- else {
- pc->draw(C,
- win->eventstate->x - ar_other->winrct.xmin,
- win->eventstate->y - ar_other->winrct.ymin,
- pc->customdata);
- }
+ wmWindow *win = CTX_wm_window(C);
+ bScreen *screen = WM_window_get_active_screen(win);
+ wmPaintCursor *pc;
+
+ if (ar->visible && ar == screen->active_region) {
+ for (pc = wm->paintcursors.first; pc; pc = pc->next) {
+ if (pc->poll == NULL || pc->poll(C)) {
+ /* Prevent drawing outside region. */
+ GLint scissor[4];
+ glGetIntegerv(GL_SCISSOR_BOX, scissor);
+ glScissor(ar->winrct.xmin,
+ ar->winrct.ymin,
+ BLI_rcti_size_x(&ar->winrct) + 1,
+ BLI_rcti_size_y(&ar->winrct) + 1);
+
+ if (ELEM(win->grabcursor, GHOST_kGrabWrap, GHOST_kGrabHide)) {
+ int x = 0, y = 0;
+ wm_get_cursor_position(win, &x, &y);
+ pc->draw(C, x, y, pc->customdata);
}
+ else {
+ pc->draw(C, win->eventstate->x, win->eventstate->y, pc->customdata);
+ }
+
+ glScissor(scissor[0], scissor[1], scissor[2], scissor[3]);
}
}
}
}
-/* ********************* drawing, swap ****************** */
-static void wm_area_mark_invalid_backbuf(ScrArea *sa)
+static bool wm_draw_region_stereo_set(Main *bmain, ScrArea *sa, ARegion *ar, eStereoViews sview)
{
- if (sa->spacetype == SPACE_VIEW3D)
- ((View3D *)sa->spacedata.first)->flag |= V3D_INVALID_BACKBUF;
+ /* We could detect better when stereo is actually needed, by inspecting the
+ * image in the image editor and sequencer. */
+ if (ar->regiontype != RGN_TYPE_WINDOW) {
+ return false;
+ }
+
+ switch (sa->spacetype) {
+ case SPACE_IMAGE:
+ {
+ SpaceImage *sima = sa->spacedata.first;
+ sima->iuser.multiview_eye = sview;
+ return true;
+ }
+ case SPACE_VIEW3D:
+ {
+ View3D *v3d = sa->spacedata.first;
+ if (v3d->camera && v3d->camera->type == OB_CAMERA) {
+ Camera *cam = v3d->camera->data;
+ CameraBGImage *bgpic = cam->bg_images.first;
+ v3d->multiview_eye = sview;
+ if (bgpic) bgpic->iuser.multiview_eye = sview;
+ return true;
+ }
+ return false;
+ }
+ case SPACE_NODE:
+ {
+ SpaceNode *snode = sa->spacedata.first;
+ if ((snode->flag & SNODE_BACKDRAW) && ED_node_is_compositor(snode)) {
+ Image *ima = BKE_image_verify_viewer(bmain, IMA_TYPE_COMPOSITE, "Viewer Node");
+ ima->eye = sview;
+ return true;
+ }
+ return false;
+ }
+ case SPACE_SEQ:
+ {
+ SpaceSeq *sseq = sa->spacedata.first;
+ sseq->multiview_eye = sview;
+ return true;
+ }
+ }
+
+ return false;
}
-static bool wm_area_test_invalid_backbuf(ScrArea *sa)
+/* ********************* drawing ****************** */
+
+static void wm_area_mark_invalid_backbuf(ScrArea *sa)
{
if (sa->spacetype == SPACE_VIEW3D)
- return (((View3D *)sa->spacedata.first)->flag & V3D_INVALID_BACKBUF) != 0;
- else
- return true;
+ ((View3D *)sa->spacedata.first)->flag |= V3D_INVALID_BACKBUF;
}
-static void wm_region_test_render_do_draw(const bScreen *screen, ScrArea *sa, ARegion *ar)
+static void wm_region_test_render_do_draw(const Scene *scene, struct Depsgraph *depsgraph,
+ ScrArea *sa, ARegion *ar)
{
/* tag region for redraw from render engine preview running inside of it */
- if (sa->spacetype == SPACE_VIEW3D) {
+ if (sa->spacetype == SPACE_VIEW3D && ar->regiontype == RGN_TYPE_WINDOW) {
RegionView3D *rv3d = ar->regiondata;
- RenderEngine *engine = (rv3d) ? rv3d->render_engine : NULL;
+ RenderEngine *engine = rv3d->render_engine;
+ GPUViewport *viewport = WM_draw_region_get_viewport(ar, 0);
if (engine && (engine->flag & RE_ENGINE_DO_DRAW)) {
- Scene *scene = screen->scene;
View3D *v3d = sa->spacedata.first;
rcti border_rect;
/* do partial redraw when possible */
- if (ED_view3d_calc_render_border(scene, v3d, ar, &border_rect))
+ if (ED_view3d_calc_render_border(scene, depsgraph, v3d, ar, &border_rect))
ED_region_tag_redraw_partial(ar, &border_rect);
else
ED_region_tag_redraw(ar);
engine->flag &= ~RE_ENGINE_DO_DRAW;
}
+ else if (viewport && GPU_viewport_do_update(viewport)) {
+ ED_region_tag_redraw(ar);
+ }
}
}
+static bool wm_region_use_viewport(ScrArea *sa, ARegion *ar)
+{
+ return (sa->spacetype == SPACE_VIEW3D && ar->regiontype == RGN_TYPE_WINDOW);
+}
+
/********************** draw all **************************/
/* - reference method, draw all each time */
@@ -198,613 +250,369 @@ static void wm_draw_callbacks(wmWindow *win)
}
}
-static void wm_method_draw_full(bContext *C, wmWindow *win)
-{
- bScreen *screen = win->screen;
- ScrArea *sa;
- ARegion *ar;
- /* draw area regions */
- for (sa = screen->areabase.first; sa; sa = sa->next) {
- CTX_wm_area_set(C, sa);
+/************************* Region drawing. ********************************
+ *
+ * Each region draws into its own framebuffer, which is then blit on the
+ * window draw buffer. This helps with fast redrawing if only some regions
+ * change. It also means we can share a single context for multiple windows,
+ * so that for example VAOs can be shared between windows. */
- for (ar = sa->regionbase.first; ar; ar = ar->next) {
- if (ar->swinid) {
- CTX_wm_region_set(C, ar);
- ED_region_do_draw(C, ar);
- ar->do_draw = false;
- wm_paintcursor_draw(C, ar);
- CTX_wm_region_set(C, NULL);
+static void wm_draw_region_buffer_free(ARegion *ar)
+{
+ if (ar->draw_buffer) {
+ for (int view = 0; view < 2; view++) {
+ if (ar->draw_buffer->offscreen[view]) {
+ GPU_offscreen_free(ar->draw_buffer->offscreen[view]);
+ }
+ if (ar->draw_buffer->viewport[view]) {
+ GPU_viewport_free(ar->draw_buffer->viewport[view]);
}
}
- wm_area_mark_invalid_backbuf(sa);
- CTX_wm_area_set(C, NULL);
+ MEM_freeN(ar->draw_buffer);
+ ar->draw_buffer = NULL;
}
-
- ED_screen_draw_edges(win);
- screen->do_draw = false;
- wm_draw_callbacks(win);
-
- /* draw overlapping regions */
- for (ar = screen->regionbase.first; ar; ar = ar->next) {
- if (ar->swinid) {
- CTX_wm_menu_set(C, ar);
- ED_region_do_draw(C, ar);
- ar->do_draw = false;
- CTX_wm_menu_set(C, NULL);
- }
- }
-
- if (screen->do_draw_gesture)
- wm_gesture_draw(win);
}
-/****************** draw overlap all **********************/
-/* - redraw marked areas, and anything that overlaps it */
-/* - it also handles swap exchange optionally, assuming */
-/* that on swap no clearing happens and we get back the */
-/* same buffer as we swapped to the front */
-
-/* mark area-regions to redraw if overlapped with rect */
-static void wm_flush_regions_down(bScreen *screen, rcti *dirty)
+static void wm_draw_offscreen_texture_parameters(GPUOffScreen *offscreen)
{
- ScrArea *sa;
- ARegion *ar;
+ /* Setup offscreen color texture for drawing. */
+ GPUTexture *texture = GPU_offscreen_color_texture(offscreen);
- for (sa = screen->areabase.first; sa; sa = sa->next) {
- for (ar = sa->regionbase.first; ar; ar = ar->next) {
- if (BLI_rcti_isect(dirty, &ar->winrct, NULL)) {
- ar->do_draw = RGN_DRAW;
- memset(&ar->drawrct, 0, sizeof(ar->drawrct));
- ar->swap = WIN_NONE_OK;
- }
- }
- }
-}
+ /* We don't support multisample textures here. */
+ BLI_assert(GPU_texture_target(texture) == GL_TEXTURE_2D);
-/* mark menu-regions to redraw if overlapped with rect */
-static void wm_flush_regions_up(bScreen *screen, rcti *dirty)
-{
- ARegion *ar;
+ glBindTexture(GL_TEXTURE_2D, GPU_texture_opengl_bindcode(texture));
- for (ar = screen->regionbase.first; ar; ar = ar->next) {
- if (BLI_rcti_isect(dirty, &ar->winrct, NULL)) {
- ar->do_draw = RGN_DRAW;
- memset(&ar->drawrct, 0, sizeof(ar->drawrct));
- ar->swap = WIN_NONE_OK;
- }
- }
+ /* No mipmaps or filtering. */
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
+ /* GL_TEXTURE_BASE_LEVEL = 0 by default */
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+
+ glBindTexture(GL_TEXTURE_2D, 0);
}
-static void wm_method_draw_overlap_all(bContext *C, wmWindow *win, int exchange)
+static void wm_draw_region_buffer_create(ARegion *ar, bool stereo, bool use_viewport)
{
- wmWindowManager *wm = CTX_wm_manager(C);
- bScreen *screen = win->screen;
- ScrArea *sa;
- ARegion *ar;
- static rcti rect = {0, 0, 0, 0};
-
- /* after backbuffer selection draw, we need to redraw */
- for (sa = screen->areabase.first; sa; sa = sa->next)
- for (ar = sa->regionbase.first; ar; ar = ar->next)
- if (ar->swinid && !wm_area_test_invalid_backbuf(sa))
- ED_region_tag_redraw(ar);
-
- /* flush overlapping regions */
- if (screen->regionbase.first) {
- /* flush redraws of area regions up to overlapping regions */
- for (sa = screen->areabase.first; sa; sa = sa->next)
- for (ar = sa->regionbase.first; ar; ar = ar->next)
- if (ar->swinid && ar->do_draw)
- wm_flush_regions_up(screen, &ar->winrct);
-
- /* flush between overlapping regions */
- for (ar = screen->regionbase.last; ar; ar = ar->prev)
- if (ar->swinid && ar->do_draw)
- wm_flush_regions_up(screen, &ar->winrct);
-
- /* flush redraws of overlapping regions down to area regions */
- for (ar = screen->regionbase.last; ar; ar = ar->prev)
- if (ar->swinid && ar->do_draw)
- wm_flush_regions_down(screen, &ar->winrct);
+ if (ar->draw_buffer) {
+ if (ar->draw_buffer->stereo != stereo) {
+ /* Free draw buffer on stereo changes. */
+ wm_draw_region_buffer_free(ar);
+ }
+ else {
+ /* Free offscreen buffer on size changes. Viewport auto resizes. */
+ GPUOffScreen *offscreen = ar->draw_buffer->offscreen[0];
+ if (offscreen && (GPU_offscreen_width(offscreen) != ar->winx ||
+ GPU_offscreen_height(offscreen) != ar->winy))
+ {
+ wm_draw_region_buffer_free(ar);
+ }
+ }
}
- /* flush drag item */
- if (rect.xmin != rect.xmax) {
- wm_flush_regions_down(screen, &rect);
- rect.xmin = rect.xmax = 0;
- }
- if (wm->drags.first) {
- /* doesnt draw, fills rect with boundbox */
- wm_drags_draw(C, win, &rect);
- }
+ if (!ar->draw_buffer) {
+ if (use_viewport) {
+ /* Allocate viewport which includes an offscreen buffer with depth
+ * multisample, etc. */
+ ar->draw_buffer = MEM_callocN(sizeof(wmDrawBuffer), "wmDrawBuffer");
+ ar->draw_buffer->viewport[0] = GPU_viewport_create();
+ ar->draw_buffer->viewport[1] = (stereo) ? GPU_viewport_create() : NULL;
+ }
+ else {
+ /* Allocate offscreen buffer if it does not exist. This one has no
+ * depth or multisample buffers. 3D view creates own buffers with
+ * the data it needs. */
+ GPUOffScreen *offscreen = GPU_offscreen_create(ar->winx, ar->winy, 0, false, false, NULL);
+ if (!offscreen) {
+ return;
+ }
- /* draw marked area regions */
- for (sa = screen->areabase.first; sa; sa = sa->next) {
- CTX_wm_area_set(C, sa);
+ wm_draw_offscreen_texture_parameters(offscreen);
- for (ar = sa->regionbase.first; ar; ar = ar->next) {
- if (ar->swinid) {
- if (ar->do_draw) {
- CTX_wm_region_set(C, ar);
- ED_region_do_draw(C, ar);
- ar->do_draw = false;
- wm_paintcursor_draw(C, ar);
- CTX_wm_region_set(C, NULL);
+ GPUOffScreen *offscreen_right = NULL;
+ if (stereo) {
+ offscreen_right = GPU_offscreen_create(ar->winx, ar->winy, 0, false, false, NULL);
- if (exchange)
- ar->swap = WIN_FRONT_OK;
+ if (!offscreen_right) {
+ GPU_offscreen_free(offscreen);
+ return;
}
- else if (exchange) {
- if (ar->swap == WIN_FRONT_OK) {
- CTX_wm_region_set(C, ar);
- ED_region_do_draw(C, ar);
- ar->do_draw = false;
- wm_paintcursor_draw(C, ar);
- CTX_wm_region_set(C, NULL);
- ar->swap = WIN_BOTH_OK;
- }
- else if (ar->swap == WIN_BACK_OK)
- ar->swap = WIN_FRONT_OK;
- else if (ar->swap == WIN_BOTH_OK)
- ar->swap = WIN_BOTH_OK;
- }
+ wm_draw_offscreen_texture_parameters(offscreen_right);
}
- }
- wm_area_mark_invalid_backbuf(sa);
- CTX_wm_area_set(C, NULL);
- }
-
- /* after area regions so we can do area 'overlay' drawing */
- if (screen->do_draw) {
- ED_screen_draw_edges(win);
- screen->do_draw = false;
- wm_draw_callbacks(win);
-
- if (exchange)
- screen->swap = WIN_FRONT_OK;
- }
- else if (exchange) {
- if (screen->swap == WIN_FRONT_OK) {
- ED_screen_draw_edges(win);
- screen->do_draw = false;
- screen->swap = WIN_BOTH_OK;
- wm_draw_callbacks(win);
+ ar->draw_buffer = MEM_callocN(sizeof(wmDrawBuffer), "wmDrawBuffer");
+ ar->draw_buffer->offscreen[0] = offscreen;
+ ar->draw_buffer->offscreen[1] = offscreen_right;
}
- else if (screen->swap == WIN_BACK_OK)
- screen->swap = WIN_FRONT_OK;
- else if (screen->swap == WIN_BOTH_OK)
- screen->swap = WIN_BOTH_OK;
- }
- /* draw marked overlapping regions */
- for (ar = screen->regionbase.first; ar; ar = ar->next) {
- if (ar->swinid && ar->do_draw) {
- CTX_wm_menu_set(C, ar);
- ED_region_do_draw(C, ar);
- ar->do_draw = false;
- CTX_wm_menu_set(C, NULL);
- }
- }
-
- if (screen->do_draw_gesture)
- wm_gesture_draw(win);
-
- /* needs pixel coords in screen */
- if (wm->drags.first) {
- wm_drags_draw(C, win, NULL);
+ ar->draw_buffer->bound_view = -1;
+ ar->draw_buffer->stereo = stereo;
}
}
-/****************** draw triple buffer ********************/
-/* - area regions are written into a texture, without any */
-/* of the overlapping menus, brushes, gestures. these */
-/* are redrawn each time. */
-
-static void wm_draw_triple_free(wmDrawTriple *triple)
+static void wm_draw_region_bind(ARegion *ar, int view)
{
- if (triple) {
- glDeleteTextures(1, &triple->bind);
- MEM_freeN(triple);
+ if (!ar->draw_buffer) {
+ return;
}
-}
-static void wm_draw_triple_fail(bContext *C, wmWindow *win)
-{
- wm_draw_window_clear(win);
+ if (ar->draw_buffer->viewport[view]) {
+ GPU_viewport_bind(ar->draw_buffer->viewport[view], &ar->winrct);
+ }
+ else {
+ GPU_offscreen_bind(ar->draw_buffer->offscreen[view], false);
+
+ /* For now scissor is expected by region drawing, we could disable it
+ * and do the enable/disable in the specific cases that setup scissor. */
+ glEnable(GL_SCISSOR_TEST);
+ glScissor(0, 0, ar->winx, ar->winy);
+ }
- win->drawfail = 1;
- wm_method_draw_overlap_all(C, win, 0);
+ ar->draw_buffer->bound_view = view;
}
-static int wm_triple_gen_textures(wmWindow *win, wmDrawTriple *triple)
+static void wm_draw_region_unbind(ARegion *ar, int view)
{
- const int winsize_x = WM_window_pixels_x(win);
- const int winsize_y = WM_window_pixels_y(win);
+ if (!ar->draw_buffer) {
+ return;
+ }
- GLint maxsize;
+ ar->draw_buffer->bound_view = -1;
- /* compute texture sizes */
- if (GLEW_ARB_texture_rectangle || GLEW_NV_texture_rectangle || GLEW_EXT_texture_rectangle) {
- triple->target = GL_TEXTURE_RECTANGLE_ARB;
+ if (ar->draw_buffer->viewport[view]) {
+ GPU_viewport_unbind(ar->draw_buffer->viewport[view]);
}
else {
- triple->target = GL_TEXTURE_2D;
+ glDisable(GL_SCISSOR_TEST);
+ GPU_offscreen_unbind(ar->draw_buffer->offscreen[view], false);
}
+}
- triple->x = winsize_x;
- triple->y = winsize_y;
-
- /* generate texture names */
- glGenTextures(1, &triple->bind);
-
- if (!triple->bind) {
- /* not the typical failure case but we handle it anyway */
- printf("WM: failed to allocate texture for triple buffer drawing (glGenTextures).\n");
- return 0;
+static void wm_draw_region_blit(ARegion *ar, int view)
+{
+ if (!ar->draw_buffer) {
+ return;
}
- /* proxy texture is only guaranteed to test for the cases that
- * there is only one texture in use, which may not be the case */
- maxsize = GPU_max_texture_size();
-
- if (triple->x > maxsize || triple->y > maxsize) {
- glBindTexture(triple->target, 0);
- printf("WM: failed to allocate texture for triple buffer drawing "
- "(texture too large for graphics card).\n");
- return 0;
+ if (ar->draw_buffer->viewport[view]) {
+ GPU_viewport_draw_to_screen(ar->draw_buffer->viewport[view], &ar->winrct);
}
-
- /* setup actual texture */
- glBindTexture(triple->target, triple->bind);
- glTexImage2D(triple->target, 0, GL_RGB8, triple->x, triple->y, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
- glTexParameteri(triple->target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glTexParameteri(triple->target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
- glBindTexture(triple->target, 0);
-
- /* not sure if this works everywhere .. */
- if (glGetError() == GL_OUT_OF_MEMORY) {
- printf("WM: failed to allocate texture for triple buffer drawing (out of memory).\n");
- return 0;
+ else {
+ GPU_offscreen_draw_to_screen(ar->draw_buffer->offscreen[view], ar->winrct.xmin, ar->winrct.ymin);
}
-
- return 1;
}
-void wm_triple_draw_textures(wmWindow *win, wmDrawTriple *triple, float alpha, bool is_interlace)
+GPUTexture *wm_draw_region_texture(ARegion *ar, int view)
{
- const int sizex = WM_window_pixels_x(win);
- const int sizey = WM_window_pixels_y(win);
-
- float halfx, halfy, ratiox, ratioy;
-
- /* wmOrtho for the screen has this same offset */
- ratiox = sizex;
- ratioy = sizey;
- halfx = GLA_PIXEL_OFS;
- halfy = GLA_PIXEL_OFS;
-
- /* texture rectangle has unnormalized coordinates */
- if (triple->target == GL_TEXTURE_2D) {
- ratiox /= triple->x;
- ratioy /= triple->y;
- halfx /= triple->x;
- halfy /= triple->y;
+ if (!ar->draw_buffer) {
+ return NULL;
}
- /* interlace stereo buffer bind the shader before calling wm_triple_draw_textures */
- if (is_interlace) {
- glEnable(triple->target);
+ if (ar->draw_buffer->viewport[view]) {
+ return GPU_viewport_color_texture(ar->draw_buffer->viewport[view]);
}
else {
- GPU_basic_shader_bind((triple->target == GL_TEXTURE_2D) ? GPU_SHADER_TEXTURE_2D : GPU_SHADER_TEXTURE_RECT);
+ return GPU_offscreen_color_texture(ar->draw_buffer->offscreen[view]);
}
+}
- glBindTexture(triple->target, triple->bind);
-
- glColor4f(1.0f, 1.0f, 1.0f, alpha);
- glBegin(GL_QUADS);
- glTexCoord2f(halfx, halfy);
- glVertex2f(0, 0);
+void wm_draw_region_blend(ARegion *ar, int view, bool blend)
+{
+ if (!ar->draw_buffer) {
+ return;
+ }
- glTexCoord2f(ratiox + halfx, halfy);
- glVertex2f(sizex, 0);
+ /* Alpha is always 1, except when blend timer is running. */
+ float alpha = ED_region_blend_alpha(ar);
+ if (alpha <= 0.0f) {
+ return;
+ }
- glTexCoord2f(ratiox + halfx, ratioy + halfy);
- glVertex2f(sizex, sizey);
+ if (!blend) {
+ alpha = 1.0f;
+ }
- glTexCoord2f(halfx, ratioy + halfy);
- glVertex2f(0, sizey);
- glEnd();
+ /* setup actual texture */
+ GPUTexture *texture = wm_draw_region_texture(ar, view);
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, GPU_texture_opengl_bindcode(texture));
- glBindTexture(triple->target, 0);
+ /* wmOrtho for the screen has this same offset */
+ const float halfx = GLA_PIXEL_OFS / (BLI_rcti_size_x(&ar->winrct) + 1);
+ const float halfy = GLA_PIXEL_OFS / (BLI_rcti_size_y(&ar->winrct) + 1);
- if (is_interlace) {
- glDisable(triple->target);
- }
- else {
- GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
+ if (blend) {
+ /* GL_ONE because regions drawn offscreen have premultiplied alpha. */
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
}
-}
-static void wm_triple_copy_textures(wmWindow *win, wmDrawTriple *triple)
-{
- const int sizex = WM_window_pixels_x(win);
- const int sizey = WM_window_pixels_y(win);
+ GPUShader *shader = GPU_shader_get_builtin_shader(GPU_SHADER_2D_IMAGE_RECT_COLOR);
+ GPU_shader_bind(shader);
- glBindTexture(triple->target, triple->bind);
- glCopyTexSubImage2D(triple->target, 0, 0, 0, 0, 0, sizex, sizey);
+ glUniform1i(GPU_shader_get_uniform(shader, "image"), 0);
+ glUniform4f(GPU_shader_get_uniform(shader, "rect_icon"), halfx, halfy, 1.0f + halfx, 1.0f + halfy);
+ glUniform4f(GPU_shader_get_uniform(shader, "rect_geom"), ar->winrct.xmin, ar->winrct.ymin, ar->winrct.xmax + 1, ar->winrct.ymax + 1);
+ glUniform4f(GPU_shader_get_builtin_uniform(shader, GWN_UNIFORM_COLOR), alpha, alpha, alpha, alpha);
- glBindTexture(triple->target, 0);
-}
+ GWN_draw_primitive(GWN_PRIM_TRI_STRIP, 4);
-static void wm_draw_region_blend(wmWindow *win, ARegion *ar, wmDrawTriple *triple)
-{
- float fac = ED_region_blend_factor(ar);
-
- /* region blend always is 1, except when blend timer is running */
- if (fac < 1.0f) {
- wmSubWindowScissorSet(win, win->screen->mainwin, &ar->winrct, true);
+ glBindTexture(GL_TEXTURE_2D, 0);
- glEnable(GL_BLEND);
- wm_triple_draw_textures(win, triple, 1.0f - fac, false);
+ if (blend) {
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_BLEND);
}
}
-static void wm_method_draw_triple(bContext *C, wmWindow *win)
+GPUViewport *WM_draw_region_get_viewport(ARegion *ar, int view)
{
- wmWindowManager *wm = CTX_wm_manager(C);
- wmDrawData *dd, *dd_next, *drawdata = win->drawdata.first;
- bScreen *screen = win->screen;
- ScrArea *sa;
- ARegion *ar;
- int copytex = false;
-
- if (drawdata && drawdata->triple) {
- glClearColor(0, 0, 0, 0);
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
-
- wmSubWindowSet(win, screen->mainwin);
-
- wm_triple_draw_textures(win, drawdata->triple, 1.0f, false);
+ if (!ar->draw_buffer) {
+ return NULL;
}
- else {
- /* we run it when we start OR when we turn stereo on */
- if (drawdata == NULL) {
- drawdata = MEM_callocN(sizeof(wmDrawData), "wmDrawData");
- BLI_addhead(&win->drawdata, drawdata);
- }
- drawdata->triple = MEM_callocN(sizeof(wmDrawTriple), "wmDrawTriple");
+ return ar->draw_buffer->viewport[view];
+}
- if (!wm_triple_gen_textures(win, drawdata->triple)) {
- wm_draw_triple_fail(C, win);
- return;
- }
+GPUViewport *WM_draw_region_get_bound_viewport(ARegion *ar)
+{
+ if (!ar->draw_buffer || ar->draw_buffer->bound_view == -1) {
+ return NULL;
}
- /* it means stereo was just turned off */
- /* note: we are removing all drawdatas that are not the first */
- for (dd = drawdata->next; dd; dd = dd_next) {
- dd_next = dd->next;
-
- BLI_remlink(&win->drawdata, dd);
- wm_draw_triple_free(dd->triple);
- MEM_freeN(dd);
- }
+ int view = ar->draw_buffer->bound_view;
+ return ar->draw_buffer->viewport[view];
+}
- wmDrawTriple *triple = drawdata->triple;
+static void wm_draw_window_offscreen(bContext *C, wmWindow *win, bool stereo)
+{
+ Main *bmain = CTX_data_main(C);
+ wmWindowManager *wm = CTX_wm_manager(C);
+ bScreen *screen = WM_window_get_active_screen(win);
- /* draw marked area regions */
- for (sa = screen->areabase.first; sa; sa = sa->next) {
+ /* Draw screen areas into own frame buffer. */
+ ED_screen_areas_iter(win, screen, sa) {
CTX_wm_area_set(C, sa);
- for (ar = sa->regionbase.first; ar; ar = ar->next) {
- if (ar->swinid && ar->do_draw) {
- if (ar->overlap == false) {
- CTX_wm_region_set(C, ar);
- ED_region_do_draw(C, ar);
- ar->do_draw = false;
- CTX_wm_region_set(C, NULL);
- copytex = true;
- }
+ /* Compute UI layouts for dynamically size regions. */
+ for (ARegion *ar = sa->regionbase.first; ar; ar = ar->next) {
+ if (ar->visible && ar->do_draw && ar->type && ar->type->layout) {
+ CTX_wm_region_set(C, ar);
+ ED_region_do_layout(C, ar);
+ CTX_wm_region_set(C, NULL);
}
}
- wm_area_mark_invalid_backbuf(sa);
- CTX_wm_area_set(C, NULL);
- }
-
- if (copytex) {
- wmSubWindowSet(win, screen->mainwin);
-
- wm_triple_copy_textures(win, triple);
- }
-
- if (wm->paintcursors.first) {
- for (sa = screen->areabase.first; sa; sa = sa->next) {
- for (ar = sa->regionbase.first; ar; ar = ar->next) {
- if (ar->swinid && ar->swinid == screen->subwinactive) {
- CTX_wm_area_set(C, sa);
- CTX_wm_region_set(C, ar);
+ ED_area_update_region_sizes(wm, win, sa);
- /* make region ready for draw, scissor, pixelspace */
- ED_region_set(C, ar);
- wm_paintcursor_draw(C, ar);
-
- CTX_wm_region_set(C, NULL);
- CTX_wm_area_set(C, NULL);
+ /* Then do actual drawing of regions. */
+ for (ARegion *ar = sa->regionbase.first; ar; ar = ar->next) {
+ if (ar->visible && ar->do_draw) {
+ CTX_wm_region_set(C, ar);
+ bool use_viewport = wm_region_use_viewport(sa, ar);
+
+ if (stereo && wm_draw_region_stereo_set(bmain, sa, ar, STEREO_LEFT_ID)) {
+ wm_draw_region_buffer_create(ar, true, use_viewport);
+
+ for (int view = 0; view < 2; view++) {
+ eStereoViews sview;
+ if (view == 0) {
+ sview = STEREO_LEFT_ID;
+ }
+ else {
+ sview = STEREO_RIGHT_ID;
+ wm_draw_region_stereo_set(bmain, sa, ar, sview);
+ }
+
+ wm_draw_region_bind(ar, view);
+ ED_region_do_draw(C, ar);
+ wm_draw_region_unbind(ar, view);
+ }
+ }
+ else {
+ wm_draw_region_buffer_create(ar, false, use_viewport);
+ wm_draw_region_bind(ar, 0);
+ ED_region_do_draw(C, ar);
+ wm_draw_region_unbind(ar, 0);
}
- }
- }
-
- wmSubWindowSet(win, screen->mainwin);
- }
-
- /* draw overlapping area regions (always like popups) */
- for (sa = screen->areabase.first; sa; sa = sa->next) {
- CTX_wm_area_set(C, sa);
- for (ar = sa->regionbase.first; ar; ar = ar->next) {
- if (ar->swinid && ar->overlap) {
- CTX_wm_region_set(C, ar);
- ED_region_do_draw(C, ar);
ar->do_draw = false;
CTX_wm_region_set(C, NULL);
-
- wm_draw_region_blend(win, ar, triple);
}
}
+ wm_area_mark_invalid_backbuf(sa);
CTX_wm_area_set(C, NULL);
}
- /* after area regions so we can do area 'overlay' drawing */
- ED_screen_draw_edges(win);
- win->screen->do_draw = false;
- wm_draw_callbacks(win);
-
- /* draw floating regions (menus) */
- for (ar = screen->regionbase.first; ar; ar = ar->next) {
- if (ar->swinid) {
+ /* Draw menus into their own framebuffer. */
+ for (ARegion *ar = screen->regionbase.first; ar; ar = ar->next) {
+ if (ar->visible) {
CTX_wm_menu_set(C, ar);
+
+ if (ar->type && ar->type->layout) {
+ /* UI code reads the OpenGL state, but we have to refesh
+ * the UI layout beforehand in case the menu size changes. */
+ wmViewport(&ar->winrct);
+ ar->type->layout(C, ar);
+ }
+
+ wm_draw_region_buffer_create(ar, false, false);
+ wm_draw_region_bind(ar, 0);
+ glClearColor(0, 0, 0, 0);
+ glClear(GL_COLOR_BUFFER_BIT);
ED_region_do_draw(C, ar);
+ wm_draw_region_unbind(ar, 0);
+
ar->do_draw = false;
CTX_wm_menu_set(C, NULL);
}
}
-
- /* always draw, not only when screen tagged */
- if (win->gesture.first)
- wm_gesture_draw(win);
-
- /* needs pixel coords in screen */
- if (wm->drags.first) {
- wm_drags_draw(C, win, NULL);
- }
}
-static void wm_method_draw_triple_multiview(bContext *C, wmWindow *win, eStereoViews sview)
+static void wm_draw_window_onscreen(bContext *C, wmWindow *win, int view)
{
- Main *bmain = CTX_data_main(C);
wmWindowManager *wm = CTX_wm_manager(C);
- wmDrawData *drawdata;
- wmDrawTriple *triple_data, *triple_all;
- bScreen *screen = win->screen;
- ScrArea *sa;
- ARegion *ar;
- int copytex = false;
- int id;
-
- /* we store the triple_data in sequence to triple_all */
- for (id = 0; id < 2; id++) {
- drawdata = BLI_findlink(&win->drawdata, (sview * 2) + id);
-
- if (drawdata && drawdata->triple) {
- if (id == 0) {
- glClearColor(0, 0, 0, 0);
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
-
- wmSubWindowSet(win, screen->mainwin);
-
- wm_triple_draw_textures(win, drawdata->triple, 1.0f, false);
- }
- }
- else {
- /* we run it when we start OR when we turn stereo on */
- if (drawdata == NULL) {
- drawdata = MEM_callocN(sizeof(wmDrawData), "wmDrawData");
- BLI_addtail(&win->drawdata, drawdata);
- }
-
- drawdata->triple = MEM_callocN(sizeof(wmDrawTriple), "wmDrawTriple");
-
- if (!wm_triple_gen_textures(win, drawdata->triple)) {
- wm_draw_triple_fail(C, win);
- return;
- }
- }
- }
-
- triple_data = ((wmDrawData *) BLI_findlink(&win->drawdata, sview * 2))->triple;
- triple_all = ((wmDrawData *) BLI_findlink(&win->drawdata, (sview * 2) + 1))->triple;
-
- /* draw marked area regions */
- for (sa = screen->areabase.first; sa; sa = sa->next) {
- CTX_wm_area_set(C, sa);
-
- switch (sa->spacetype) {
- case SPACE_IMAGE:
- {
- SpaceImage *sima = sa->spacedata.first;
- sima->iuser.multiview_eye = sview;
- break;
- }
- case SPACE_VIEW3D:
- {
- View3D *v3d = sa->spacedata.first;
- BGpic *bgpic = v3d->bgpicbase.first;
- v3d->multiview_eye = sview;
- if (bgpic) bgpic->iuser.multiview_eye = sview;
- break;
- }
- case SPACE_NODE:
- {
- SpaceNode *snode = sa->spacedata.first;
- if ((snode->flag & SNODE_BACKDRAW) && ED_node_is_compositor(snode)) {
- Image *ima = BKE_image_verify_viewer(bmain, IMA_TYPE_COMPOSITE, "Viewer Node");
- ima->eye = sview;
+ bScreen *screen = WM_window_get_active_screen(win);
+
+ /* Draw into the window framebuffer, in full window coordinates. */
+ wmWindowViewport(win);
+ glClearColor(0, 0, 0, 0);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ /* Blit non-overlapping area regions. */
+ ED_screen_areas_iter(win, screen, sa) {
+ for (ARegion *ar = sa->regionbase.first; ar; ar = ar->next) {
+ if (ar->visible && ar->overlap == false) {
+ if (view == -1 && ar->draw_buffer && ar->draw_buffer->stereo) {
+ /* Stereo drawing from textures. */
+ if (win->stereo3d_format->display_mode == S3D_DISPLAY_ANAGLYPH) {
+ wm_stereo3d_draw_anaglyph(win, ar);
+ }
+ else {
+ wm_stereo3d_draw_interlace(win, ar);
+ }
}
- break;
- }
- case SPACE_SEQ:
- {
- SpaceSeq *sseq = sa->spacedata.first;
- sseq->multiview_eye = sview;
- break;
- }
- }
-
- /* draw marked area regions */
- for (ar = sa->regionbase.first; ar; ar = ar->next) {
- if (ar->swinid && ar->do_draw) {
-
- if (ar->overlap == false) {
- CTX_wm_region_set(C, ar);
- ED_region_do_draw(C, ar);
-
- if (sview == STEREO_RIGHT_ID)
- ar->do_draw = false;
-
- CTX_wm_region_set(C, NULL);
- copytex = true;
+ else {
+ /* Blit from offscreen buffer. */
+ wm_draw_region_blit(ar, 0);
}
}
}
-
- wm_area_mark_invalid_backbuf(sa);
- CTX_wm_area_set(C, NULL);
- }
-
- if (copytex) {
- wmSubWindowSet(win, screen->mainwin);
-
- wm_triple_copy_textures(win, triple_data);
}
+ /* Draw paint cursors. */
if (wm->paintcursors.first) {
- for (sa = screen->areabase.first; sa; sa = sa->next) {
- for (ar = sa->regionbase.first; ar; ar = ar->next) {
- if (ar->swinid && ar->swinid == screen->subwinactive) {
+ ED_screen_areas_iter(win, screen, sa) {
+ for (ARegion *ar = sa->regionbase.first; ar; ar = ar->next) {
+ if (ar->visible && ar == screen->active_region) {
CTX_wm_area_set(C, sa);
CTX_wm_region_set(C, ar);
/* make region ready for draw, scissor, pixelspace */
- ED_region_set(C, ar);
wm_paintcursor_draw(C, ar);
CTX_wm_region_set(C, NULL);
@@ -813,42 +621,26 @@ static void wm_method_draw_triple_multiview(bContext *C, wmWindow *win, eStereoV
}
}
- wmSubWindowSet(win, screen->mainwin);
+ wmWindowViewport(win);
}
- /* draw overlapping area regions (always like popups) */
- for (sa = screen->areabase.first; sa; sa = sa->next) {
- CTX_wm_area_set(C, sa);
-
- for (ar = sa->regionbase.first; ar; ar = ar->next) {
- if (ar->swinid && ar->overlap) {
- CTX_wm_region_set(C, ar);
- ED_region_do_draw(C, ar);
- if (sview == STEREO_RIGHT_ID)
- ar->do_draw = false;
- CTX_wm_region_set(C, NULL);
-
- wm_draw_region_blend(win, ar, triple_data);
+ /* Blend in overlapping area regions */
+ ED_screen_areas_iter(win, screen, sa) {
+ for (ARegion *ar = sa->regionbase.first; ar; ar = ar->next) {
+ if (ar->visible && ar->overlap) {
+ wm_draw_region_blend(ar, 0, true);
}
}
-
- CTX_wm_area_set(C, NULL);
}
- /* after area regions so we can do area 'overlay' drawing */
+ /* After area regions so we can do area 'overlay' drawing. */
ED_screen_draw_edges(win);
- if (sview == STEREO_RIGHT_ID)
- win->screen->do_draw = false;
wm_draw_callbacks(win);
- /* draw floating regions (menus) */
- for (ar = screen->regionbase.first; ar; ar = ar->next) {
- if (ar->swinid) {
- CTX_wm_menu_set(C, ar);
- ED_region_do_draw(C, ar);
- if (sview == STEREO_RIGHT_ID)
- ar->do_draw = false;
- CTX_wm_menu_set(C, NULL);
+ /* Blend in floating regions (menus). */
+ for (ARegion *ar = screen->regionbase.first; ar; ar = ar->next) {
+ if (ar->visible) {
+ wm_draw_region_blend(ar, 0, true);
}
}
@@ -860,10 +652,76 @@ static void wm_method_draw_triple_multiview(bContext *C, wmWindow *win, eStereoV
if (wm->drags.first) {
wm_drags_draw(C, win, NULL);
}
+}
+
+static void wm_draw_window(bContext *C, wmWindow *win)
+{
+ bScreen *screen = WM_window_get_active_screen(win);
+ bool stereo = WM_stereo3d_enabled(win, false);
+
+ /* Draw area regions into their own framebuffer. This way we can redraw
+ * the areas that need it, and blit the rest from existing framebuffers. */
+ wm_draw_window_offscreen(C, win, stereo);
+
+ /* Now we draw into the window framebuffer, in full window coordinates. */
+ if (!stereo) {
+ /* Regular mono drawing. */
+ wm_draw_window_onscreen(C, win, -1);
+ }
+ else if (win->stereo3d_format->display_mode == S3D_DISPLAY_PAGEFLIP) {
+ /* For pageflip we simply draw to both back buffers. */
+ glDrawBuffer(GL_BACK_LEFT);
+ wm_draw_window_onscreen(C, win, 0);
+ glDrawBuffer(GL_BACK_RIGHT);
+ wm_draw_window_onscreen(C, win, 1);
+ glDrawBuffer(GL_BACK);
+ }
+ else if (ELEM(win->stereo3d_format->display_mode, S3D_DISPLAY_ANAGLYPH, S3D_DISPLAY_INTERLACE)) {
+ /* For anaglyph and interlace, we draw individual regions with
+ * stereo framebuffers using different shaders. */
+ wm_draw_window_onscreen(C, win, -1);
+ }
+ else {
+ /* For side-by-side and top-bottom, we need to render each view to an
+ * an offscreen texture and then draw it. This used to happen for all
+ * stereo methods, but it's less efficient than drawing directly. */
+ const int width = WM_window_pixels_x(win);
+ const int height = WM_window_pixels_y(win);
+ GPUOffScreen *offscreen = GPU_offscreen_create(width, height, 0, false, false, NULL);
+
+ if (offscreen) {
+ GPUTexture *texture = GPU_offscreen_color_texture(offscreen);
+ wm_draw_offscreen_texture_parameters(offscreen);
+
+ for (int view = 0; view < 2; view++) {
+ /* Draw view into offscreen buffer. */
+ GPU_offscreen_bind(offscreen, false);
+ wm_draw_window_onscreen(C, win, view);
+ GPU_offscreen_unbind(offscreen, false);
+
+ /* Draw offscreen buffer to screen. */
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, GPU_texture_opengl_bindcode(texture));
+
+ if (win->stereo3d_format->display_mode == S3D_DISPLAY_SIDEBYSIDE) {
+ wm_stereo3d_draw_sidebyside(win, view);
+ }
+ else {
+ wm_stereo3d_draw_topbottom(win, view);
+ }
+
+ glBindTexture(GL_TEXTURE_2D, 0);
+ }
+
+ GPU_offscreen_free(offscreen);
+ }
+ else {
+ /* Still draw something in case of allocation failure. */
+ wm_draw_window_onscreen(C, win, 0);
+ }
+ }
- /* copy the ui + overlays */
- wmSubWindowSet(win, screen->mainwin);
- wm_triple_copy_textures(win, triple_all);
+ screen->do_draw = false;
}
/****************** main update call **********************/
@@ -871,25 +729,27 @@ static void wm_method_draw_triple_multiview(bContext *C, wmWindow *win, eStereoV
/* quick test to prevent changing window drawable */
static bool wm_draw_update_test_window(wmWindow *win)
{
- const bScreen *screen = win->screen;
- ScrArea *sa;
+ Scene *scene = WM_window_get_active_scene(win);
+ ViewLayer *view_layer = WM_window_get_active_view_layer(win);
+ struct Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer, true);
+ bScreen *screen = WM_window_get_active_screen(win);
ARegion *ar;
bool do_draw = false;
for (ar = screen->regionbase.first; ar; ar = ar->next) {
if (ar->do_draw_overlay) {
- wm_tag_redraw_overlay(win, ar);
+ screen->do_draw_paintcursor = true;
ar->do_draw_overlay = false;
}
- if (ar->swinid && ar->do_draw)
+ if (ar->visible && ar->do_draw)
do_draw = true;
}
- for (sa = screen->areabase.first; sa; sa = sa->next) {
+ ED_screen_areas_iter(win, screen, sa) {
for (ar = sa->regionbase.first; ar; ar = ar->next) {
- wm_region_test_render_do_draw(screen, sa, ar);
+ wm_region_test_render_do_draw(scene, depsgraph, sa, ar);
- if (ar->swinid && ar->do_draw)
+ if (ar->visible && ar->do_draw)
do_draw = true;
}
}
@@ -911,41 +771,14 @@ static bool wm_draw_update_test_window(wmWindow *win)
return false;
}
-static int wm_automatic_draw_method(wmWindow *win)
+void WM_paint_cursor_tag_redraw(wmWindow *win, ARegion *UNUSED(ar))
{
- /* We assume all supported GPUs now support triple buffer well. */
- if (win->drawmethod == USER_DRAW_AUTOMATIC) {
- return USER_DRAW_TRIPLE;
- }
- else {
- return win->drawmethod;
- }
-}
-
-bool WM_is_draw_triple(wmWindow *win)
-{
- /* function can get called before this variable is set in drawing code below */
- if (win->drawmethod != U.wmdrawmethod)
- win->drawmethod = U.wmdrawmethod;
- return (USER_DRAW_TRIPLE == wm_automatic_draw_method(win));
-}
-
-void wm_tag_redraw_overlay(wmWindow *win, ARegion *ar)
-{
- /* for draw triple gestures, paint cursors don't need region redraw */
- if (ar && win) {
- if (wm_automatic_draw_method(win) != USER_DRAW_TRIPLE)
- ED_region_tag_redraw(ar);
- win->screen->do_draw_paintcursor = true;
+ if (win) {
+ bScreen *screen = WM_window_get_active_screen(win);
+ screen->do_draw_paintcursor = true;
}
}
-void WM_paint_cursor_tag_redraw(wmWindow *win, ARegion *ar)
-{
- win->screen->do_draw_paintcursor = true;
- wm_tag_redraw_overlay(win, ar);
-}
-
void wm_draw_update(bContext *C)
{
Main *bmain = CTX_data_main(C);
@@ -970,13 +803,9 @@ void wm_draw_update(bContext *C)
continue;
}
#endif
- if (win->drawmethod != U.wmdrawmethod) {
- wm_draw_window_clear(win);
- win->drawmethod = U.wmdrawmethod;
- }
if (wm_draw_update_test_window(win)) {
- bScreen *screen = win->screen;
+ bScreen *screen = WM_window_get_active_screen(win);
CTX_wm_window_set(C, win);
@@ -984,29 +813,9 @@ void wm_draw_update(bContext *C)
wm_window_make_drawable(wm, win);
/* notifiers for screen redraw */
- if (screen->do_refresh)
- ED_screen_refresh(wm, win);
-
- int drawmethod = wm_automatic_draw_method(win);
-
- if (win->drawfail)
- wm_method_draw_overlap_all(C, win, 0);
- else if (drawmethod == USER_DRAW_FULL)
- wm_method_draw_full(C, win);
- else if (drawmethod == USER_DRAW_OVERLAP)
- wm_method_draw_overlap_all(C, win, 0);
- else if (drawmethod == USER_DRAW_OVERLAP_FLIP)
- wm_method_draw_overlap_all(C, win, 1);
- else { /* USER_DRAW_TRIPLE */
- if ((WM_stereo3d_enabled(win, false)) == false) {
- wm_method_draw_triple(C, win);
- }
- else {
- wm_method_draw_triple_multiview(C, win, STEREO_LEFT_ID);
- wm_method_draw_triple_multiview(C, win, STEREO_RIGHT_ID);
- wm_method_draw_stereo3d(C, win);
- }
- }
+ ED_screen_ensure_updated(wm, win, screen);
+
+ wm_draw_window(C, win);
screen->do_draw_gesture = false;
screen->do_draw_paintcursor = false;
@@ -1019,42 +828,16 @@ void wm_draw_update(bContext *C)
}
}
-void wm_draw_data_free(wmWindow *win)
+void wm_draw_region_clear(wmWindow *win, ARegion *UNUSED(ar))
{
- wmDrawData *dd;
-
- for (dd = win->drawdata.first; dd; dd = dd->next) {
- wm_draw_triple_free(dd->triple);
- }
- BLI_freelistN(&win->drawdata);
+ bScreen *screen = WM_window_get_active_screen(win);
+ screen->do_draw = true;
}
-void wm_draw_window_clear(wmWindow *win)
+void WM_draw_region_free(ARegion *ar)
{
- bScreen *screen = win->screen;
- ScrArea *sa;
- ARegion *ar;
-
- wm_draw_data_free(win);
-
- /* clear screen swap flags */
- if (screen) {
- for (sa = screen->areabase.first; sa; sa = sa->next)
- for (ar = sa->regionbase.first; ar; ar = ar->next)
- ar->swap = WIN_NONE_OK;
-
- screen->swap = WIN_NONE_OK;
- }
-}
-
-void wm_draw_region_clear(wmWindow *win, ARegion *ar)
-{
- int drawmethod = wm_automatic_draw_method(win);
-
- if (ELEM(drawmethod, USER_DRAW_OVERLAP, USER_DRAW_OVERLAP_FLIP))
- wm_flush_regions_down(win->screen, &ar->winrct);
-
- win->screen->do_draw = true;
+ wm_draw_region_buffer_free(ar);
+ ar->visible = 0;
}
void WM_redraw_windows(bContext *C)
diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c
index 3a300877750..8469dc9da0e 100644
--- a/source/blender/windowmanager/intern/wm_event_system.c
+++ b/source/blender/windowmanager/intern/wm_event_system.c
@@ -55,10 +55,12 @@
#include "BKE_context.h"
#include "BKE_idprop.h"
#include "BKE_global.h"
+#include "BKE_layer.h"
#include "BKE_main.h"
#include "BKE_report.h"
#include "BKE_scene.h"
#include "BKE_screen.h"
+#include "BKE_workspace.h"
#include "BKE_sound.h"
@@ -71,14 +73,15 @@
#include "RNA_access.h"
-#include "GPU_debug.h"
-
#include "UI_interface.h"
#include "PIL_time.h"
#include "WM_api.h"
#include "WM_types.h"
+#include "WM_message.h"
+#include "WM_toolsystem.h"
+
#include "wm.h"
#include "wm_window.h"
#include "wm_event_system.h"
@@ -86,6 +89,8 @@
#include "RNA_enum_types.h"
+#include "DEG_depsgraph.h"
+
/* Motion in pixels allowed before we don't consider single/double click. */
#define WM_EVENT_CLICK_WIGGLE_ROOM 2
@@ -182,7 +187,6 @@ static bool wm_test_duplicate_notifier(wmWindowManager *wm, unsigned int type, v
/* XXX: in future, which notifiers to send to other windows? */
void WM_event_add_notifier(const bContext *C, unsigned int type, void *reference)
{
- ARegion *ar;
wmWindowManager *wm = CTX_wm_manager(C);
wmNotifier *note;
@@ -196,10 +200,6 @@ void WM_event_add_notifier(const bContext *C, unsigned int type, void *reference
note->window = CTX_wm_window(C);
- ar = CTX_wm_region(C);
- if (ar)
- note->swinid = ar->swinid;
-
note->category = type & NOTE_CATEGORY;
note->data = type & NOTE_DATA;
note->subtype = type & NOTE_SUBTYPE;
@@ -250,6 +250,14 @@ void WM_main_remove_notifier_reference(const void *reference)
wm_notifier_clear(note);
}
}
+
+ /* Remap instead. */
+#if 0
+ if (wm->message_bus) {
+ WM_msg_id_remove(wm->message_bus, reference);
+ }
+#endif
+
}
}
@@ -269,6 +277,17 @@ void WM_main_remap_editor_id_reference(ID *old_id, ID *new_id)
}
}
}
+
+ wmWindowManager *wm = bmain->wm.first;
+ if (wm && wm->message_bus) {
+ struct wmMsgBus *mbus = wm->message_bus;
+ if (new_id != NULL) {
+ WM_msg_id_update(mbus, old_id, new_id);
+ }
+ else {
+ WM_msg_id_remove(mbus, old_id);
+ }
+ }
}
static void wm_notifier_clear(wmNotifier *note)
@@ -277,31 +296,23 @@ static void wm_notifier_clear(wmNotifier *note)
memset(((char *)note) + sizeof(Link), 0, sizeof(*note) - sizeof(Link));
}
-/**
- * Was part of #wm_event_do_notifiers, split out so it can be called once before entering the #WM_main loop.
- * This ensures operators don't run before the UI and depsgraph are initialized.
- */
-void wm_event_do_refresh_wm_and_depsgraph(bContext *C)
+void wm_event_do_depsgraph(bContext *C)
{
wmWindowManager *wm = CTX_wm_manager(C);
uint64_t win_combine_v3d_datamask = 0;
/* combine datamasks so 1 win doesn't disable UV's in another [#26448] */
for (wmWindow *win = wm->windows.first; win; win = win->next) {
- win_combine_v3d_datamask |= ED_view3d_screen_datamask(win->screen);
+ const Scene *scene = WM_window_get_active_scene(win);
+ const bScreen *screen = WM_window_get_active_screen(win);
+
+ win_combine_v3d_datamask |= ED_view3d_screen_datamask(scene, screen);
}
/* cached: editor refresh callbacks now, they get context */
for (wmWindow *win = wm->windows.first; win; win = win->next) {
- ScrArea *sa;
-
- CTX_wm_window_set(C, win);
- for (sa = win->screen->areabase.first; sa; sa = sa->next) {
- if (sa->do_refresh) {
- CTX_wm_area_set(C, sa);
- ED_area_do_refresh(C, sa);
- }
- }
+ Scene *scene = WM_window_get_active_scene(win);
+ ViewLayer *view_layer = WM_window_get_active_view_layer(win);
/* XXX make lock in future, or separated derivedmesh users in scene */
if (G.is_rendering == false) {
@@ -309,14 +320,46 @@ void wm_event_do_refresh_wm_and_depsgraph(bContext *C)
Main *bmain = CTX_data_main(C);
/* copied to set's in scene_update_tagged_recursive() */
- win->screen->scene->customdata_mask = win_combine_v3d_datamask;
+ scene->customdata_mask = win_combine_v3d_datamask;
/* XXX, hack so operators can enforce datamasks [#26482], gl render */
- win->screen->scene->customdata_mask |= win->screen->scene->customdata_mask_modal;
+ scene->customdata_mask |= scene->customdata_mask_modal;
- BKE_scene_update_tagged(bmain->eval_ctx, bmain, win->screen->scene);
+ /* TODO(sergey): For now all dependency graphs which are evaluated from
+ * workspace are considered active. This will work all fine with "locked"
+ * view layer and time across windows. This is to be granted separately,
+ * and for until then we have to accept ambiguities when object is shared
+ * across visible view layers and has overrides on it.
+ */
+ Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer, true);
+ DEG_make_active(depsgraph);
+ BKE_scene_graph_update_tagged(depsgraph, bmain);
}
}
+}
+
+/**
+ * Was part of #wm_event_do_notifiers, split out so it can be called once before entering the #WM_main loop.
+ * This ensures operators don't run before the UI and depsgraph are initialized.
+ */
+void wm_event_do_refresh_wm_and_depsgraph(bContext *C)
+{
+ wmWindowManager *wm = CTX_wm_manager(C);
+ /* cached: editor refresh callbacks now, they get context */
+ for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ const bScreen *screen = WM_window_get_active_screen(win);
+ ScrArea *sa;
+
+ CTX_wm_window_set(C, win);
+ for (sa = screen->areabase.first; sa; sa = sa->next) {
+ if (sa->do_refresh) {
+ CTX_wm_area_set(C, sa);
+ ED_area_do_refresh(C, sa);
+ }
+ }
+ }
+
+ wm_event_do_depsgraph(C);
CTX_wm_window_set(C, NULL);
}
@@ -331,8 +374,11 @@ void wm_event_do_notifiers(bContext *C)
if (wm == NULL)
return;
+ /* disable? - keep for now since its used for window level notifiers. */
+#if 1
/* cache & catch WM level notifiers, such as frame change, scene/screen set */
for (win = wm->windows.first; win; win = win->next) {
+ Scene *scene = WM_window_get_active_scene(win);
bool do_anim = false;
CTX_wm_window_set(C, win);
@@ -350,23 +396,46 @@ void wm_event_do_notifiers(bContext *C)
}
if (note->window == win) {
if (note->category == NC_SCREEN) {
- if (note->data == ND_SCREENBROWSE) {
+ if (note->data == ND_WORKSPACE_SET) {
+ WorkSpace *ref_ws = note->reference;
+
+ UI_popup_handlers_remove_all(C, &win->modalhandlers);
+
+ WM_window_set_active_workspace(C, win, ref_ws);
+ if (G.debug & G_DEBUG_EVENTS)
+ printf("%s: Workspace set %p\n", __func__, note->reference);
+ }
+ else if (note->data == ND_WORKSPACE_DELETE) {
+ WorkSpace *workspace = note->reference;
+
+ ED_workspace_delete(workspace, CTX_data_main(C), C, wm); // XXX hrms, think this over!
+ if (G.debug & G_DEBUG_EVENTS)
+ printf("%s: Workspace delete %p\n", __func__, workspace);
+ }
+ else if (note->data == ND_LAYOUTBROWSE) {
+ bScreen *ref_screen = BKE_workspace_layout_screen_get(note->reference);
+
/* free popup handlers only [#35434] */
UI_popup_handlers_remove_all(C, &win->modalhandlers);
- ED_screen_set(C, note->reference); // XXX hrms, think this over!
- CLOG_INFO(WM_LOG_EVENTS, 1, "screen set %p", note->reference);
+ ED_screen_change(C, ref_screen); /* XXX hrms, think this over! */
+ if (G.debug & G_DEBUG_EVENTS)
+ printf("%s: screen set %p\n", __func__, note->reference);
}
- else if (note->data == ND_SCREENDELETE) {
- ED_screen_delete(C, note->reference); // XXX hrms, think this over!
- CLOG_INFO(WM_LOG_EVENTS, 1, "screen delete %p", note->reference);
+ else if (note->data == ND_LAYOUTDELETE) {
+ WorkSpace *workspace = WM_window_get_active_workspace(win);
+ WorkSpaceLayout *layout = note->reference;
+
+ ED_workspace_layout_delete(workspace, layout, C); // XXX hrms, think this over!
+ if (G.debug & G_DEBUG_EVENTS)
+ printf("%s: screen delete %p\n", __func__, note->reference);
}
}
}
if (note->window == win ||
- (note->window == NULL && (note->reference == NULL || note->reference == win->screen->scene)))
+ (note->window == NULL && (note->reference == NULL || note->reference == scene)))
{
if (note->category == NC_SCENE) {
if (note->data == ND_FRAME)
@@ -374,19 +443,20 @@ void wm_event_do_notifiers(bContext *C)
}
}
if (ELEM(note->category, NC_SCENE, NC_OBJECT, NC_GEOM, NC_WM)) {
- ED_info_stats_clear(win->screen->scene);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ ED_info_stats_clear(view_layer);
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_INFO, NULL);
}
}
if (do_anim) {
/* XXX, quick frame changes can cause a crash if framechange and rendering
- * collide (happens on slow scenes), BKE_scene_update_for_newframe can be called
+ * collide (happens on slow scenes), BKE_scene_graph_update_for_newframe can be called
* twice which can depgraph update the same object at once */
if (G.is_rendering == false) {
-
/* depsgraph gets called, might send more notifiers */
- ED_update_for_newframe(CTX_data_main(C), win->screen->scene, 1);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ ED_update_for_newframe(CTX_data_main(C), depsgraph);
}
}
}
@@ -394,16 +464,23 @@ void wm_event_do_notifiers(bContext *C)
/* the notifiers are sent without context, to keep it clean */
while ((note = BLI_pophead(&wm->queue))) {
for (win = wm->windows.first; win; win = win->next) {
+ Scene *scene = WM_window_get_active_scene(win);
+ bScreen *screen = WM_window_get_active_screen(win);
+ WorkSpace *workspace = WM_window_get_active_workspace(win);
/* filter out notifiers */
- if (note->category == NC_SCREEN && note->reference && note->reference != win->screen) {
+ if (note->category == NC_SCREEN &&
+ note->reference &&
+ note->reference != screen &&
+ note->reference != workspace &&
+ note->reference != WM_window_get_active_layout(win))
+ {
/* pass */
}
- else if (note->category == NC_SCENE && note->reference && note->reference != win->screen->scene) {
+ else if (note->category == NC_SCENE && note->reference && note->reference != scene) {
/* pass */
}
else {
- ScrArea *sa;
ARegion *ar;
/* XXX context in notifiers? */
@@ -412,14 +489,14 @@ void wm_event_do_notifiers(bContext *C)
/* printf("notifier win %d screen %s cat %x\n", win->winid, win->screen->id.name + 2, note->category); */
ED_screen_do_listen(C, note);
- for (ar = win->screen->regionbase.first; ar; ar = ar->next) {
- ED_region_do_listen(win->screen, NULL, ar, note);
+ for (ar = screen->regionbase.first; ar; ar = ar->next) {
+ ED_region_do_listen(win, NULL, ar, note, scene);
}
- for (sa = win->screen->areabase.first; sa; sa = sa->next) {
- ED_area_do_listen(win->screen, sa, note);
+ ED_screen_areas_iter(win, screen, sa) {
+ ED_area_do_listen(win, sa, note, scene);
for (ar = sa->regionbase.first; ar; ar = ar->next) {
- ED_region_do_listen(win->screen, sa, ar, note);
+ ED_region_do_listen(win, sa, ar, note, scene);
}
}
}
@@ -427,8 +504,26 @@ void wm_event_do_notifiers(bContext *C)
MEM_freeN(note);
}
+#endif /* if 1 (postpone disabling for in favor of message-bus), eventually. */
+
+ /* Handle message bus. */
+ {
+ for (win = wm->windows.first; win; win = win->next) {
+ CTX_wm_window_set(C, win);
+ WM_msgbus_handle(wm->message_bus, C);
+ }
+ CTX_wm_window_set(C, NULL);
+ }
wm_event_do_refresh_wm_and_depsgraph(C);
+
+ /* Status bar */
+ if (wm->winactive) {
+ win = wm->winactive;
+ CTX_wm_window_set(C, win);
+ WM_window_cursor_keymap_status_refresh(C, win);
+ CTX_wm_window_set(C, NULL);
+ }
}
static int wm_event_always_pass(const wmEvent *event)
@@ -546,6 +641,39 @@ bool WM_operator_poll_context(bContext *C, wmOperatorType *ot, short context)
return wm_operator_call_internal(C, ot, NULL, NULL, context, true);
}
+bool WM_operator_check_ui_empty(wmOperatorType *ot)
+{
+ if (ot->macro.first != NULL) {
+ /* for macros, check all have exec() we can call */
+ wmOperatorTypeMacro *otmacro;
+ for (otmacro = ot->macro.first; otmacro; otmacro = otmacro->next) {
+ wmOperatorType *otm = WM_operatortype_find(otmacro->idname, 0);
+ if (otm && !WM_operator_check_ui_empty(otm)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /* Assume a ui callback will draw something. */
+ if (ot->ui) {
+ return false;
+ }
+
+ PointerRNA ptr;
+ WM_operator_properties_create_ptr(&ptr, ot);
+ RNA_STRUCT_BEGIN (&ptr, prop)
+ {
+ int flag = RNA_property_flag(prop);
+ if (flag & PROP_HIDDEN) {
+ continue;
+ }
+ return false;
+ }
+ RNA_STRUCT_END;
+ return true;
+}
+
/**
* Sets the active region for this space from the context.
*
@@ -687,7 +815,7 @@ void WM_reportf(ReportType type, const char *format, ...)
/* (caller_owns_reports == true) when called from python */
static void wm_operator_reports(bContext *C, wmOperator *op, int retval, bool caller_owns_reports)
{
- if (caller_owns_reports == false) { /* popup */
+ if (G.background == 0 && caller_owns_reports == false) { /* popup */
if (op->reports->list.first) {
/* FIXME, temp setting window, see other call to UI_popup_menu_reports for why */
wmWindow *win_prev = CTX_wm_window(C);
@@ -740,6 +868,7 @@ static bool wm_operator_register_check(wmWindowManager *wm, wmOperatorType *ot)
static void wm_operator_finished(bContext *C, wmOperator *op, const bool repeat, const bool store)
{
wmWindowManager *wm = CTX_wm_manager(C);
+ enum { NOP, SET, CLEAR, } hud_status = NOP;
op->customdata = NULL;
@@ -751,10 +880,19 @@ static void wm_operator_finished(bContext *C, wmOperator *op, const bool repeat,
* called from operators that already do an undo push. usually
* this will happen for python operators that call C operators */
if (wm->op_undo_depth == 0) {
- if (op->type->flag & OPTYPE_UNDO)
+ if (op->type->flag & OPTYPE_UNDO) {
ED_undo_push_op(C, op);
- else if (op->type->flag & OPTYPE_UNDO_GROUPED)
+ if (repeat == 0) {
+ hud_status = CLEAR;
+ }
+ }
+ else if (op->type->flag & OPTYPE_UNDO_GROUPED) {
ED_undo_grouped_push_op(C, op);
+ if (repeat == 0) {
+ hud_status = CLEAR;
+ }
+ }
+
}
if (repeat == 0) {
@@ -770,11 +908,29 @@ static void wm_operator_finished(bContext *C, wmOperator *op, const bool repeat,
wm_operator_register(C, op);
WM_operator_region_active_win_set(C);
+
+ /* Show the redo panel. */
+ hud_status = SET;
}
else {
WM_operator_free(op);
}
}
+
+ if (hud_status != NOP) {
+ if (hud_status == SET) {
+ ScrArea *sa = CTX_wm_area(C);
+ if (sa) {
+ ED_area_type_hud_ensure(C, sa);
+ }
+ }
+ else if (hud_status == CLEAR) {
+ ED_area_type_hud_clear(wm, NULL);
+ }
+ else {
+ BLI_assert(0);
+ }
+ }
}
/* if repeat is true, it doesn't register again, nor does it free */
@@ -1127,7 +1283,8 @@ bool WM_operator_last_properties_store(wmOperator *UNUSED(op))
*/
static int wm_operator_invoke(
bContext *C, wmOperatorType *ot, wmEvent *event,
- PointerRNA *properties, ReportList *reports, const bool poll_only)
+ PointerRNA *properties, ReportList *reports,
+ const bool poll_only, bool use_last_properties)
{
int retval = OPERATOR_PASS_THROUGH;
@@ -1145,14 +1302,14 @@ static int wm_operator_invoke(
}
/* initialize setting from previous run */
- if (!is_nested_call) { /* not called by py script */
+ if (!is_nested_call && use_last_properties) { /* not called by py script */
WM_operator_last_properties_init(op);
}
if ((event == NULL) || (event->type != MOUSEMOVE)) {
CLOG_INFO(WM_LOG_HANDLERS, 2,
- "handle evt %d win %d op %s",
- event ? event->type : 0, CTX_wm_screen(C)->subwinactive, ot->idname);
+ "handle evt %d win %p op %s",
+ event ? event->type : 0, CTX_wm_screen(C)->active_region, ot->idname);
}
if (op->type->invoke && event) {
@@ -1193,7 +1350,7 @@ static int wm_operator_invoke(
/* do nothing, wm_operator_exec() has been called somewhere */
}
else if (retval & OPERATOR_FINISHED) {
- const bool store = !is_nested_call;
+ const bool store = !is_nested_call && use_last_properties;
wm_operator_finished(C, op, false, store);
}
else if (retval & OPERATOR_RUNNING_MODAL) {
@@ -1356,7 +1513,7 @@ static int wm_operator_call_internal(
CTX_wm_region_set(C, ar1);
}
- retval = wm_operator_invoke(C, ot, event, properties, reports, poll_only);
+ retval = wm_operator_invoke(C, ot, event, properties, reports, poll_only, true);
/* set region back */
CTX_wm_region_set(C, ar);
@@ -1370,7 +1527,7 @@ static int wm_operator_call_internal(
ARegion *ar = CTX_wm_region(C);
CTX_wm_region_set(C, NULL);
- retval = wm_operator_invoke(C, ot, event, properties, reports, poll_only);
+ retval = wm_operator_invoke(C, ot, event, properties, reports, poll_only, true);
CTX_wm_region_set(C, ar);
return retval;
@@ -1384,7 +1541,7 @@ static int wm_operator_call_internal(
CTX_wm_region_set(C, NULL);
CTX_wm_area_set(C, NULL);
- retval = wm_operator_invoke(C, ot, event, properties, reports, poll_only);
+ retval = wm_operator_invoke(C, ot, event, properties, reports, poll_only, true);
CTX_wm_area_set(C, area);
CTX_wm_region_set(C, ar);
@@ -1392,7 +1549,7 @@ static int wm_operator_call_internal(
}
case WM_OP_EXEC_DEFAULT:
case WM_OP_INVOKE_DEFAULT:
- return wm_operator_invoke(C, ot, event, properties, reports, poll_only);
+ return wm_operator_invoke(C, ot, event, properties, reports, poll_only, true);
}
}
@@ -1489,17 +1646,22 @@ void wm_event_free_handler(wmEventHandler *handler)
/* only set context when area/region is part of screen */
static void wm_handler_op_context(bContext *C, wmEventHandler *handler, const wmEvent *event)
{
+ wmWindow *win = CTX_wm_window(C);
bScreen *screen = CTX_wm_screen(C);
if (screen && handler->op) {
if (handler->op_area == NULL)
CTX_wm_area_set(C, NULL);
else {
- ScrArea *sa;
+ ScrArea *sa = NULL;
- for (sa = screen->areabase.first; sa; sa = sa->next)
- if (sa == handler->op_area)
+ ED_screen_areas_iter(win, screen, sa_iter) {
+ if (sa_iter == handler->op_area) {
+ sa = sa_iter;
break;
+ }
+ }
+
if (sa == NULL) {
/* when changing screen layouts with running modal handlers (like render display), this
* is not an error to print */
@@ -1808,6 +1970,11 @@ static int wm_handler_operator_call(bContext *C, ListBase *handlers, wmEventHand
if (retval & (OPERATOR_CANCELLED | OPERATOR_FINISHED)) {
wm_operator_reports(C, op, retval, false);
+
+ if (op->type->modalkeymap) {
+ wmWindow *win = CTX_wm_window(C);
+ WM_window_status_area_tag_redraw(win);
+ }
}
else {
/* not very common, but modal operators may report before finishing */
@@ -1837,6 +2004,9 @@ static int wm_handler_operator_call(bContext *C, ListBase *handlers, wmEventHand
CTX_wm_region_set(C, NULL);
}
+ /* update manipulators during modal handlers */
+ wm_manipulatormaps_handled_modal_update(C, event, handler);
+
/* remove modal handler, operator itself should have been canceled and freed */
if (retval & (OPERATOR_CANCELLED | OPERATOR_FINISHED)) {
WM_cursor_grab_disable(CTX_wm_window(C), NULL);
@@ -1856,9 +2026,21 @@ static int wm_handler_operator_call(bContext *C, ListBase *handlers, wmEventHand
else {
wmOperatorType *ot = WM_operatortype_find(event->keymap_idname, 0);
- if (ot) {
- if (wm_operator_check_locked_interface(C, ot)) {
- retval = wm_operator_invoke(C, ot, event, properties, NULL, false);
+ if (ot && wm_operator_check_locked_interface(C, ot)) {
+ bool use_last_properties = true;
+ PointerRNA tool_properties = {{0}};
+ bool use_tool_properties = (handler->keymap_tool != NULL);
+
+ if (use_tool_properties) {
+ WM_toolsystem_ref_properties_init_for_keymap(handler->keymap_tool, &tool_properties, properties, ot);
+ properties = &tool_properties;
+ use_last_properties = false;
+ }
+
+ retval = wm_operator_invoke(C, ot, event, properties, NULL, false, use_last_properties);
+
+ if (use_tool_properties) {
+ WM_operator_properties_free(&tool_properties);
}
}
}
@@ -1890,9 +2072,10 @@ static int wm_handler_fileselect_do(bContext *C, ListBase *handlers, wmEventHand
{
ScrArea *sa;
- /* sa can be null when window A is active, but mouse is over window B */
- /* in this case, open file select in original window A */
- if (handler->op_area == NULL) {
+ /* sa can be null when window A is active, but mouse is over window B
+ * in this case, open file select in original window A. Also don't
+ * use global areas. */
+ if (handler->op_area == NULL || ED_area_is_global(handler->op_area)) {
bScreen *screen = CTX_wm_screen(C);
sa = (ScrArea *)screen->areabase.first;
}
@@ -2132,6 +2315,7 @@ static int wm_handlers_do_intern(bContext *C, wmEvent *event, ListBase *handlers
for (kmi = keymap->items.first; kmi; kmi = kmi->next) {
if (wm_eventmatch(event, kmi)) {
+ struct wmEventHandler_KeymapFn keymap_callback = handler->keymap_callback;
PRINT("%s: item matched '%s'\n", __func__, kmi->idname);
@@ -2139,9 +2323,13 @@ static int wm_handlers_do_intern(bContext *C, wmEvent *event, ListBase *handlers
event->keymap_idname = kmi->idname;
action |= wm_handler_operator_call(C, handlers, handler, event, kmi->ptr);
+
if (action & WM_HANDLER_BREAK) {
/* not always_pass here, it denotes removed handler */
CLOG_INFO(WM_LOG_HANDLERS, 2, "handled! '%s'", kmi->idname);
+ if (keymap_callback.handle_post_fn != NULL) {
+ keymap_callback.handle_post_fn(keymap, kmi, keymap_callback.user_data);
+ }
break;
}
else {
@@ -2204,6 +2392,143 @@ static int wm_handlers_do_intern(bContext *C, wmEvent *event, ListBase *handlers
}
}
}
+ else if (handler->manipulator_map) {
+ ScrArea *area = CTX_wm_area(C);
+ ARegion *region = CTX_wm_region(C);
+ wmManipulatorMap *mmap = handler->manipulator_map;
+ wmManipulator *mpr = wm_manipulatormap_highlight_get(mmap);
+
+ if (region->manipulator_map != handler->manipulator_map) {
+ WM_manipulatormap_tag_refresh(handler->manipulator_map);
+ }
+
+ wm_manipulatormap_handler_context(C, handler);
+ wm_region_mouse_co(C, event);
+
+ /* handle manipulator highlighting */
+ if (event->type == MOUSEMOVE && !wm_manipulatormap_modal_get(mmap)) {
+ int part;
+ mpr = wm_manipulatormap_highlight_find(mmap, C, event, &part);
+ if (wm_manipulatormap_highlight_set(mmap, C, mpr, part) && mpr != NULL) {
+ WM_tooltip_timer_init(C, CTX_wm_window(C), region, WM_manipulatormap_tooltip_init);
+ }
+ }
+ else {
+ /* Either we operate on a single highlighted item
+ * or groups attached to the selected manipulators.
+ * To simplify things both cases loop over an array of items. */
+ wmManipulatorGroup *mgroup_first;
+ bool is_mgroup_single;
+
+ if (ISMOUSE(event->type)) {
+ /* Keep mpr set as-is, just fake single selection. */
+ if (mpr) {
+ mgroup_first = mpr->parent_mgroup;
+ }
+ else {
+ mgroup_first = NULL;
+ }
+ is_mgroup_single = true;
+ }
+ else {
+ if (WM_manipulatormap_is_any_selected(mmap)) {
+ const ListBase *groups = WM_manipulatormap_group_list(mmap);
+ mgroup_first = groups->first;
+ }
+ else {
+ mgroup_first = NULL;
+ }
+ is_mgroup_single = false;
+ }
+
+ /* Don't use from now on. */
+ mpr = NULL;
+
+ for (wmManipulatorGroup *mgroup = mgroup_first; mgroup; mgroup = mgroup->next) {
+ /* get user customized keymap from default one */
+
+ if ((is_mgroup_single == false) &&
+ /* We might want to change the logic here and use some kind of manipulator edit-mode.
+ * For now just use keymap when a selection exists. */
+ wm_manipulatorgroup_is_any_selected(mgroup) == false)
+ {
+ continue;
+ }
+
+ wmKeyMap *keymap = WM_keymap_active(wm, mgroup->type->keymap);
+ wmKeyMapItem *kmi;
+
+ PRINT("%s: checking '%s' ...", __func__, keymap->idname);
+
+ if (WM_keymap_poll(C, keymap)) {
+ PRINT("pass\n");
+ for (kmi = keymap->items.first; kmi; kmi = kmi->next) {
+ if (wm_eventmatch(event, kmi)) {
+ struct wmEventHandler_KeymapFn keymap_callback = handler->keymap_callback;
+ wmOperator *op = handler->op;
+
+ PRINT("%s: item matched '%s'\n", __func__, kmi->idname);
+
+ /* weak, but allows interactive callback to not use rawkey */
+ event->keymap_idname = kmi->idname;
+
+ CTX_wm_manipulator_group_set(C, mgroup);
+
+ /* handler->op is called later, we want keymap op to be triggered here */
+ handler->op = NULL;
+ action |= wm_handler_operator_call(C, handlers, handler, event, kmi->ptr);
+ handler->op = op;
+
+ CTX_wm_manipulator_group_set(C, NULL);
+
+ if (action & WM_HANDLER_BREAK) {
+ if (keymap_callback.handle_post_fn != NULL) {
+ keymap_callback.handle_post_fn(keymap, kmi, keymap_callback.user_data);
+ }
+
+ if (G.debug & (G_DEBUG_EVENTS | G_DEBUG_HANDLERS)) {
+ printf("%s: handled - and pass on! '%s'\n",
+ __func__, kmi->idname);
+ }
+ break;
+ }
+ else {
+ if (action & WM_HANDLER_HANDLED) {
+ if (G.debug & (G_DEBUG_EVENTS | G_DEBUG_HANDLERS)) {
+ printf("%s: handled - and pass on! '%s'\n",
+ __func__, kmi->idname);
+ }
+ }
+ else {
+ PRINT("%s: un-handled '%s'\n",
+ __func__, kmi->idname);
+ }
+ }
+ }
+ }
+ }
+ else {
+ PRINT("fail\n");
+ }
+
+ if (action & WM_HANDLER_BREAK) {
+ break;
+ }
+
+ if (is_mgroup_single) {
+ break;
+ }
+ }
+ }
+
+ /* restore the area */
+ CTX_wm_area_set(C, area);
+ CTX_wm_region_set(C, region);
+
+ if (handler->op) {
+ action |= wm_handler_operator_call(C, handlers, handler, event, NULL);
+ }
+ }
else {
/* modal, swallows all */
action |= wm_handler_operator_call(C, handlers, handler, event, NULL);
@@ -2360,13 +2685,15 @@ static int wm_event_inside_i(wmEvent *event, rcti *rect)
static ScrArea *area_event_inside(bContext *C, const int xy[2])
{
+ wmWindow *win = CTX_wm_window(C);
bScreen *screen = CTX_wm_screen(C);
- ScrArea *sa;
- if (screen)
- for (sa = screen->areabase.first; sa; sa = sa->next)
+ if (screen) {
+ ED_screen_areas_iter(win, screen, sa) {
if (BLI_rcti_isect_pt_v(&sa->totrct, xy))
return sa;
+ }
+ }
return NULL;
}
@@ -2424,17 +2751,19 @@ static void wm_paintcursor_test(bContext *C, const wmEvent *event)
static void wm_event_drag_test(wmWindowManager *wm, wmWindow *win, wmEvent *event)
{
+ bScreen *screen = WM_window_get_active_screen(win);
+
if (BLI_listbase_is_empty(&wm->drags)) {
return;
}
if (event->type == MOUSEMOVE || ISKEYMODIFIER(event->type)) {
- win->screen->do_draw_drag = true;
+ screen->do_draw_drag = true;
}
else if (event->type == ESCKEY) {
WM_drag_free_list(&wm->drags);
- win->screen->do_draw_drag = true;
+ screen->do_draw_drag = true;
}
else if (event->type == LEFTMOUSE && event->val == KM_RELEASE) {
event->type = EVT_DROP;
@@ -2450,17 +2779,11 @@ static void wm_event_drag_test(wmWindowManager *wm, wmWindow *win, wmEvent *even
event->customdatafree = 1;
/* clear drop icon */
- win->screen->do_draw_drag = true;
+ screen->do_draw_drag = true;
/* restore cursor (disabled, see wm_dragdrop.c) */
// WM_cursor_modal_restore(win);
}
-
- /* overlap fails otherwise */
- if (win->screen->do_draw_drag)
- if (win->drawmethod == USER_DRAW_OVERLAP)
- win->screen->do_draw = true;
-
}
/* filter out all events of the pie that spawned the last pie unless it's a release event */
@@ -2480,6 +2803,40 @@ static bool wm_event_pie_filter(wmWindow *win, const wmEvent *event)
}
}
+#ifdef USE_WORKSPACE_TOOL
+static void wm_event_manipulator_temp_handler_apply(
+ bContext *C, ScrArea *sa, ARegion *ar, wmEventHandler *sneaky_handler)
+{
+ if (ar->regiontype == RGN_TYPE_WINDOW) {
+ bToolRef_Runtime *tref_rt = sa->runtime.tool ? sa->runtime.tool->runtime : NULL;
+ if (tref_rt && tref_rt->keymap[0]) {
+ wmKeyMap *km = WM_keymap_find_all(
+ C, tref_rt->keymap, sa->spacetype, RGN_TYPE_WINDOW);
+ if (km != NULL) {
+ sneaky_handler->keymap = km;
+ sneaky_handler->keymap_tool = sa->runtime.tool;
+
+ /* Handle widgets first. */
+ wmEventHandler *handler_last = ar->handlers.last;
+ while (handler_last && handler_last->manipulator_map == NULL) {
+ handler_last = handler_last->prev;
+ }
+ /* Head of list or after last manipulator. */
+ BLI_insertlinkafter(&ar->handlers, handler_last, sneaky_handler);
+ }
+ }
+ }
+}
+
+static void wm_event_manipulator_temp_handler_clear(
+ bContext *UNUSED(C), ScrArea *UNUSED(sa), ARegion *ar, wmEventHandler *sneaky_handler)
+{
+ if (sneaky_handler->keymap) {
+ BLI_remlink(&ar->handlers, sneaky_handler);
+ }
+}
+#endif /* USE_WORKSPACE_TOOL */
+
/* called in main loop */
/* goes over entire hierarchy: events -> window -> screen -> area -> region */
void wm_event_do_handlers(bContext *C)
@@ -2489,22 +2846,28 @@ void wm_event_do_handlers(bContext *C)
/* update key configuration before handling events */
WM_keyconfig_update(wm);
+ WM_manipulatorconfig_update(CTX_data_main(C));
for (win = wm->windows.first; win; win = win->next) {
+ bScreen *screen = WM_window_get_active_screen(win);
wmEvent *event;
- if (win->screen == NULL)
+ /* some safty checks - these should always be set! */
+ BLI_assert(WM_window_get_active_scene(win));
+ BLI_assert(WM_window_get_active_screen(win));
+ BLI_assert(WM_window_get_active_workspace(win));
+
+ if (screen == NULL)
wm_event_free_all(win);
else {
- Scene *scene = win->screen->scene;
+ Scene *scene = WM_window_get_active_scene(win);
if (scene) {
- int is_playing_sound = BKE_sound_scene_playing(win->screen->scene);
+ int is_playing_sound = BKE_sound_scene_playing(scene);
if (is_playing_sound != -1) {
bool is_playing_screen;
CTX_wm_window_set(C, win);
- CTX_wm_screen_set(C, win->screen);
CTX_data_scene_set(C, scene);
is_playing_screen = (ED_screen_animation_playing(wm) != NULL);
@@ -2521,7 +2884,8 @@ void wm_event_do_handlers(bContext *C)
int ncfra = time * (float)FPS + 0.5f;
if (ncfra != scene->r.cfra) {
scene->r.cfra = ncfra;
- ED_update_for_newframe(CTX_data_main(C), scene, 1);
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+ ED_update_for_newframe(CTX_data_main(C), depsgraph);
WM_event_add_notifier(C, NC_WINDOW, NULL);
}
}
@@ -2537,9 +2901,11 @@ void wm_event_do_handlers(bContext *C)
while ( (event = win->queue.first) ) {
int action = WM_HANDLER_CONTINUE;
+ /* active screen might change during handlers, update pointer */
+ screen = WM_window_get_active_screen(win);
+
if (G.debug & (G_DEBUG_HANDLERS | G_DEBUG_EVENTS) && !ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) {
printf("\n%s: Handling event\n", __func__);
-
WM_event_print(event);
}
@@ -2556,7 +2922,7 @@ void wm_event_do_handlers(bContext *C)
CTX_wm_window_set(C, win);
/* Clear tool-tip on mouse move. */
- if (win->screen->tool_tip && win->screen->tool_tip->exit_on_event) {
+ if (screen->tool_tip && screen->tool_tip->exit_on_event) {
if (ISMOUSE(event->type)) {
WM_tooltip_clear(C, win);
}
@@ -2580,8 +2946,7 @@ void wm_event_do_handlers(bContext *C)
return;
/* check for a tooltip */
- {
- bScreen *screen = CTX_wm_window(C)->screen;
+ if (screen == WM_window_get_active_screen(win)) {
if (screen->tool_tip && screen->tool_tip->timer) {
if ((event->type == TIMER) && (event->customdata == screen->tool_tip->timer)) {
WM_tooltip_init(C, win);
@@ -2596,13 +2961,12 @@ void wm_event_do_handlers(bContext *C)
wm_tweakevent_test(C, event, action);
if ((action & WM_HANDLER_BREAK) == 0) {
- ScrArea *sa;
ARegion *ar;
/* Note: setting subwin active should be done here, after modal handlers have been done */
if (event->type == MOUSEMOVE) {
/* state variables in screen, cursors. Also used in wm_draw.c, fails for modal handlers though */
- ED_screen_set_subwinactive(C, event);
+ ED_screen_set_active_region(C, win, &event->x);
/* for regions having custom cursors */
wm_paintcursor_test(C, event);
}
@@ -2612,12 +2976,12 @@ void wm_event_do_handlers(bContext *C)
}
#endif
- for (sa = win->screen->areabase.first; sa; sa = sa->next) {
+ ED_screen_areas_iter(win, screen, sa) {
/* after restoring a screen from SCREENMAXIMIZED we have to wait
* with the screen handling till the region coordinates are updated */
- if (win->screen->skip_handling == true) {
+ if (screen->skip_handling == true) {
/* restore for the next iteration of wm_event_do_handlers */
- win->screen->skip_handling = false;
+ screen->skip_handling = false;
break;
}
@@ -2645,8 +3009,27 @@ void wm_event_do_handlers(bContext *C)
}
}
+#ifdef USE_WORKSPACE_TOOL
+ /* How to solve properly?
+ *
+ * Handlers are stored in each region,
+ * however the tool-system swaps keymaps often and isn't stored
+ * per region.
+ *
+ * Need to investigate how this could be done better.
+ * We might need to add a more dynamic handler type that uses a callback
+ * to fetch its current keymap.
+ */
+ wmEventHandler sneaky_handler = {NULL};
+ wm_event_manipulator_temp_handler_apply(C, sa, ar, &sneaky_handler);
+#endif /* USE_WORKSPACE_TOOL */
+
action |= wm_handlers_do(C, event, &ar->handlers);
+#ifdef USE_WORKSPACE_TOOL
+ wm_event_manipulator_temp_handler_clear(C, sa, ar, &sneaky_handler);
+#endif /* USE_WORKSPACE_TOOL */
+
/* fileread case (python), [#29489] */
if (CTX_wm_window(C) == NULL)
return;
@@ -2711,8 +3094,7 @@ void wm_event_do_handlers(bContext *C)
/* update key configuration after handling events */
WM_keyconfig_update(wm);
-
- GPU_ASSERT_NO_GL_ERRORS("wm_event_do_handlers");
+ WM_manipulatorconfig_update(CTX_data_main(C));
}
/* ********** filesector handling ************ */
@@ -2754,24 +3136,26 @@ void WM_event_add_fileselect(bContext *C, wmOperator *op)
if (handler->type == WM_HANDLER_FILESELECT) {
bScreen *screen = CTX_wm_screen(C);
- ScrArea *sa;
+ bool cancel_handler = true;
/* find the area with the file selector for this handler */
- for (sa = screen->areabase.first; sa; sa = sa->next) {
+ ED_screen_areas_iter(win, screen, sa) {
if (sa->spacetype == SPACE_FILE) {
SpaceFile *sfile = sa->spacedata.first;
if (sfile->op == handler->op) {
CTX_wm_area_set(C, sa);
wm_handler_fileselect_do(C, &win->modalhandlers, handler, EVT_FILESELECT_CANCEL);
+ cancel_handler = false;
break;
}
}
}
/* if not found we stop the handler without changing the screen */
- if (!sa)
+ if (cancel_handler) {
wm_handler_fileselect_do(C, &win->modalhandlers, handler, EVT_FILESELECT_EXTERNAL_CANCEL);
+ }
}
}
@@ -2822,9 +3206,41 @@ wmEventHandler *WM_event_add_modal_handler(bContext *C, wmOperator *op)
BLI_addhead(&win->modalhandlers, handler);
+ if (op->type->modalkeymap) {
+ WM_window_status_area_tag_redraw(win);
+ }
+
return handler;
}
+/**
+ * Modal handlers store a pointer to an area which might be freed while the handler runs.
+ * Use this function to NULL all handler pointers to \a old_area.
+ */
+void WM_event_modal_handler_area_replace(wmWindow *win, const ScrArea *old_area, ScrArea *new_area)
+{
+ for (wmEventHandler *handler = win->modalhandlers.first; handler; handler = handler->next) {
+ /* fileselect handler is quite special... it needs to keep old area stored in handler, so don't change it */
+ if ((handler->op_area == old_area) && (handler->type != WM_HANDLER_FILESELECT)) {
+ handler->op_area = new_area;
+ }
+ }
+}
+
+/**
+ * Modal handlers store a pointer to a region which might be freed while the handler runs.
+ * Use this function to NULL all handler pointers to \a old_region.
+ */
+void WM_event_modal_handler_region_replace(wmWindow *win, const ARegion *old_region, ARegion *new_region)
+{
+ for (wmEventHandler *handler = win->modalhandlers.first; handler; handler = handler->next) {
+ if (handler->op_region == old_region) {
+ handler->op_region = new_region;
+ handler->op_region_type = new_region ? new_region->regiontype : RGN_TYPE_WINDOW;
+ }
+ }
+}
+
wmEventHandler *WM_event_add_keymap_handler(ListBase *handlers, wmKeyMap *keymap)
{
wmEventHandler *handler;
@@ -2884,6 +3300,15 @@ void WM_event_remove_keymap_handler(ListBase *handlers, wmKeyMap *keymap)
}
}
+void WM_event_set_keymap_handler_callback(
+ wmEventHandler *handler,
+ void (keymap_tag)(wmKeyMap *keymap, wmKeyMapItem *kmi, void *user_data),
+ void *user_data)
+{
+ handler->keymap_callback.handle_post_fn = keymap_tag;
+ handler->keymap_callback.user_data = user_data;
+}
+
wmEventHandler *WM_event_add_ui_handler(
const bContext *C, ListBase *handlers,
wmUIHandlerFunc ui_handle, wmUIHandlerRemoveFunc ui_remove,
@@ -3829,3 +4254,345 @@ bool WM_event_is_ime_switch(const struct wmEvent *event)
#endif
/** \} */
+
+
+static wmKeyMapItem *wm_kmi_from_event(
+ bContext *C, wmWindowManager *wm,
+ ListBase *handlers, const wmEvent *event)
+{
+ for (wmEventHandler *handler = handlers->first; handler; handler = handler->next) {
+ /* during this loop, ui handlers for nested menus can tag multiple handlers free */
+ if (handler->flag & WM_HANDLER_DO_FREE) {
+ /* pass */
+ }
+ else if (handler_boundbox_test(handler, event)) { /* optional boundbox */
+ if (handler->keymap) {
+ wmKeyMap *keymap = WM_keymap_active(wm, handler->keymap);
+ if (WM_keymap_poll(C, keymap)) {
+ for (wmKeyMapItem *kmi = keymap->items.first; kmi; kmi = kmi->next) {
+ if (wm_eventmatch(event, kmi)) {
+ wmOperatorType *ot = WM_operatortype_find(kmi->idname, 0);
+ if (WM_operator_poll_context(C, ot, WM_OP_INVOKE_DEFAULT)) {
+ return kmi;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ return NULL;
+}
+
+/* -------------------------------------------------------------------- */
+/** \name Cursor Keymap Status
+ *
+ * Show cursor keys in the status bar.
+ * This is done by detecting changes to the state - full keymap lookups are expensive
+ * so only perform this on changing tools, space types, pressing different modifier keys... etc.
+ * \{ */
+
+/** State storage to detect changes between calls to refresh the information. */
+struct CursorKeymapInfo_State {
+ struct {
+ short shift, ctrl, alt, oskey;
+ } modifiers;
+ short space_type;
+ short region_type;
+ /* Never use, just compare memory for changes. */
+ bToolRef tref;
+};
+
+struct CursorKeymapInfo {
+ /* 0: mouse button index
+ * 1: event type (click/press, drag)
+ * 2: text.
+ */
+ char text[3][2][128];
+ wmEvent state_event;
+ struct CursorKeymapInfo_State state;
+};
+
+static void wm_event_cursor_store(
+ struct CursorKeymapInfo_State *state,
+ const wmEvent *event,
+ short space_type, short region_type,
+ const bToolRef *tref)
+{
+ state->modifiers.shift = event->shift;
+ state->modifiers.ctrl = event->ctrl;
+ state->modifiers.alt = event->alt;
+ state->modifiers.oskey = event->oskey;
+ state->space_type = space_type;
+ state->region_type = region_type;
+ state->tref = tref ? *tref : (bToolRef){0};
+}
+
+const char *WM_window_cursor_keymap_status_get(const wmWindow *win, int button_index, int type_index)
+{
+ if (win->cursor_keymap_status != NULL) {
+ struct CursorKeymapInfo *cd = win->cursor_keymap_status;
+ const char *msg = cd->text[button_index][type_index];
+ if (*msg) {
+ return msg;
+ }
+ }
+ return NULL;
+}
+
+/**
+ * Similar to #BKE_screen_area_map_find_area_xy and related functions,
+ * use here since the ara is stored in the window manager.
+ */
+ScrArea *WM_window_status_area_find(wmWindow *win, bScreen *screen)
+{
+ if (screen->state == SCREENFULL) {
+ return NULL;
+ }
+ ScrArea *sa_statusbar = NULL;
+ for (ScrArea *sa = win->global_areas.areabase.first; sa; sa = sa->next) {
+ if (sa->spacetype == SPACE_STATUSBAR) {
+ sa_statusbar = sa;
+ break;
+ }
+ }
+ return sa_statusbar;
+}
+
+void WM_window_status_area_tag_redraw(wmWindow *win)
+{
+ bScreen *sc = WM_window_get_active_screen(win);
+ ScrArea *sa = WM_window_status_area_find(win, sc);
+ if (sa != NULL) {
+ ED_area_tag_redraw(sa);
+ }
+}
+
+void WM_window_cursor_keymap_status_refresh(bContext *C, wmWindow *win)
+{
+ bScreen *screen = WM_window_get_active_screen(win);
+ ScrArea *sa_statusbar = WM_window_status_area_find(win, screen);
+ if (sa_statusbar == NULL) {
+ return;
+ }
+
+ struct CursorKeymapInfo *cd;
+ if (UNLIKELY(win->cursor_keymap_status == NULL)) {
+ win->cursor_keymap_status = MEM_callocN(sizeof(struct CursorKeymapInfo), __func__);
+ }
+ cd = win->cursor_keymap_status;
+
+ /* Detect unchanged state (early exit). */
+ if (memcmp(&cd->state_event, win->eventstate, sizeof(wmEvent)) == 0) {
+ return;
+ }
+
+ /* Now perform more comprehensive check,
+ * still keep this fast since it happens on mouse-move. */
+ struct CursorKeymapInfo cd_prev = *((struct CursorKeymapInfo *)win->cursor_keymap_status);
+ cd->state_event = *win->eventstate;
+
+ /* Find active region and associated area. */
+ ARegion *ar = screen->active_region;
+ if (ar == NULL) {
+ return;
+ }
+
+ ScrArea *sa = NULL;
+ ED_screen_areas_iter(win, screen, sa_iter) {
+ if (BLI_findindex(&sa_iter->regionbase, ar) != -1) {
+ sa = sa_iter;
+ break;
+ }
+ }
+ if (sa == NULL) {
+ return;
+ }
+
+ /* Keep as-is. */
+ if (ELEM(sa->spacetype, SPACE_STATUSBAR, SPACE_TOPBAR)) {
+ return;
+ }
+ if (ELEM(ar->regiontype, RGN_TYPE_HEADER, RGN_TYPE_TEMPORARY, RGN_TYPE_HUD)) {
+ return;
+ }
+ /* Fallback to window. */
+ if (ELEM(ar->regiontype, RGN_TYPE_TOOLS, RGN_TYPE_TOOL_PROPS)) {
+ ar = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW);
+ }
+
+ /* Detect changes to the state. */
+ {
+ bToolRef *tref = NULL;
+ if (ar->regiontype == RGN_TYPE_WINDOW) {
+ ViewLayer *view_layer = WM_window_get_active_view_layer(win);
+ WorkSpace *workspace = WM_window_get_active_workspace(win);
+ const bToolKey tkey = {
+ .space_type = sa->spacetype,
+ .mode = WM_toolsystem_mode_from_spacetype(view_layer, sa, sa->spacetype),
+ };
+ tref = WM_toolsystem_ref_find(workspace, &tkey);
+ }
+ wm_event_cursor_store(&cd->state, win->eventstate, sa->spacetype, ar->regiontype, tref);
+ if (memcmp(&cd->state, &cd_prev.state, sizeof(cd->state)) == 0) {
+ return;
+ }
+ }
+
+ /* Changed context found, detect changes to keymap and refresh the status bar. */
+ const struct {
+ int button_index;
+ int type_index; /* 0: press or click, 1: drag. */
+ int event_type;
+ int event_value;
+ } event_data[] = {
+ {0, 0, LEFTMOUSE, KM_PRESS},
+ {0, 0, LEFTMOUSE, KM_CLICK},
+ {0, 1, EVT_TWEAK_L, KM_ANY},
+
+ {1, 0, MIDDLEMOUSE, KM_PRESS},
+ {1, 0, MIDDLEMOUSE, KM_CLICK},
+ {1, 1, EVT_TWEAK_M, KM_ANY},
+
+ {2, 0, RIGHTMOUSE, KM_PRESS},
+ {2, 0, RIGHTMOUSE, KM_CLICK},
+ {2, 1, EVT_TWEAK_R, KM_ANY},
+ };
+
+ for (int button_index = 0; button_index < 3; button_index++) {
+ cd->text[button_index][0][0] = '\0';
+ cd->text[button_index][1][0] = '\0';
+ }
+
+ CTX_wm_window_set(C, win);
+ CTX_wm_area_set(C, sa);
+ CTX_wm_region_set(C, ar);
+
+#ifdef USE_WORKSPACE_TOOL
+ wmEventHandler sneaky_handler = {NULL};
+ wm_event_manipulator_temp_handler_apply(C, sa, ar, &sneaky_handler);
+#endif
+
+ ListBase *handlers[] = {
+ &ar->handlers,
+ &sa->handlers,
+ &win->handlers,
+ };
+
+ wmWindowManager *wm = CTX_wm_manager(C);
+ for (int data_index = 0; data_index < ARRAY_SIZE(event_data); data_index++) {
+ const int button_index = event_data[data_index].button_index;
+ const int type_index = event_data[data_index].type_index;
+ if (cd->text[button_index][type_index][0] != 0) {
+ continue;
+ }
+ wmEvent test_event = *win->eventstate;
+ test_event.type = event_data[data_index].event_type;
+ test_event.val = event_data[data_index].event_value;
+ wmKeyMapItem *kmi = NULL;
+ for (int handler_index = 0; handler_index < ARRAY_SIZE(handlers); handler_index++) {
+ kmi = wm_kmi_from_event(C, wm, handlers[handler_index], &test_event);
+ if (kmi) {
+ break;
+ }
+ }
+ if (kmi) {
+ wmOperatorType *ot = WM_operatortype_find(kmi->idname, 0);
+ STRNCPY(cd->text[button_index][type_index], ot ? ot->name : kmi->idname);
+ }
+ }
+
+#ifdef USE_WORKSPACE_TOOL
+ wm_event_manipulator_temp_handler_clear(C, sa, ar, &sneaky_handler);
+#endif
+
+ if (memcmp(&cd_prev.text, &cd->text, sizeof(cd_prev.text)) != 0) {
+ ED_area_tag_redraw(sa_statusbar);
+ }
+
+ CTX_wm_window_set(C, NULL);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Modal Keymap Status
+ *
+ * \{ */
+
+bool WM_window_modal_keymap_status_draw(
+ bContext *UNUSED(C), wmWindow *win,
+ uiLayout *layout)
+{
+ wmKeyMap *keymap = NULL;
+ wmOperator *op = NULL;
+ for (wmEventHandler *handler = win->modalhandlers.first; handler; handler = handler->next) {
+ if (handler->op) {
+ /* 'handler->keymap' could be checked too, seems not to be used. */
+ wmKeyMap *keymap_test = handler->op->type->modalkeymap;
+ if (keymap_test && keymap_test->modal_items) {
+ keymap = keymap_test;
+ op = handler->op;
+ break;
+ }
+ }
+ }
+ if (keymap == NULL) {
+ return false;
+ }
+ const EnumPropertyItem *items = keymap->modal_items;
+
+ uiLayout *row = uiLayoutRow(layout, true);
+ for (int i = 0; items[i].identifier; i++) {
+ if (!items[i].identifier[0]) {
+ continue;
+ }
+ if ((keymap->poll_modal_item != NULL) &&
+ (keymap->poll_modal_item(op, items[i].value) == false))
+ {
+ continue;
+ }
+
+ bool show_text = true;
+
+ {
+ /* warning: O(n^2) */
+ wmKeyMapItem *kmi = NULL;
+ for (kmi = keymap->items.first; kmi; kmi = kmi->next) {
+ if (kmi->propvalue == items[i].value) {
+ break;
+ }
+ }
+ if (kmi != NULL) {
+ if (kmi->val == KM_RELEASE) {
+ /* Assume release events just disable something which was toggled on. */
+ continue;
+ }
+ int icon_mod[4];
+ int icon = UI_icon_from_keymap_item(kmi, icon_mod);
+ if (icon != 0) {
+ for (int j = 0; j < ARRAY_SIZE(icon_mod) && icon_mod[j]; j++) {
+ uiItemL(row, "", icon_mod[j]);
+ }
+ uiItemL(row, items[i].name, icon);
+ show_text = false;
+ }
+ }
+ }
+ if (show_text) {
+ char buf[UI_MAX_DRAW_STR];
+ int available_len = sizeof(buf);
+ char *p = buf;
+ WM_modalkeymap_operator_items_to_string_buf(
+ op->type, items[i].value, true, UI_MAX_SHORTCUT_STR, &available_len, &p);
+ p -= 1;
+ if (p > buf) {
+ BLI_snprintf(p, available_len, ": %s", items[i].name);
+ uiItemL(row, buf, 0);
+ }
+ }
+ }
+ return true;
+}
+
+/** \} */
diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c
index 19b48e3f79e..84dcf30e63c 100644
--- a/source/blender/windowmanager/intern/wm_files.c
+++ b/source/blender/windowmanager/intern/wm_files.c
@@ -70,6 +70,7 @@
#include "DNA_scene_types.h"
#include "DNA_screen_types.h"
#include "DNA_windowmanager_types.h"
+#include "DNA_workspace_types.h"
#include "BKE_appdir.h"
#include "BKE_autoexec.h"
@@ -77,7 +78,6 @@
#include "BKE_blendfile.h"
#include "BKE_blender_undo.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
#include "BKE_global.h"
#include "BKE_library.h"
#include "BKE_main.h"
@@ -87,6 +87,7 @@
#include "BKE_scene.h"
#include "BKE_screen.h"
#include "BKE_undo_system.h"
+#include "BKE_workspace.h"
#include "BLO_readfile.h"
#include "BLO_writefile.h"
@@ -122,8 +123,13 @@
#include "BPY_extern.h"
#endif
+#include "DEG_depsgraph.h"
+
#include "WM_api.h"
#include "WM_types.h"
+#include "WM_message.h"
+#include "WM_toolsystem.h"
+
#include "wm.h"
#include "wm_files.h"
#include "wm_window.h"
@@ -162,7 +168,7 @@ static void wm_window_match_init(bContext *C, ListBase *wmlist)
CTX_wm_window_set(C, win); /* needed by operator close callbacks */
WM_event_remove_handlers(C, &win->handlers);
WM_event_remove_handlers(C, &win->modalhandlers);
- ED_screen_exit(C, win, win->screen);
+ ED_screen_exit(C, win, WM_window_get_active_screen(win));
}
}
@@ -177,36 +183,26 @@ static void wm_window_match_init(bContext *C, ListBase *wmlist)
CTX_wm_menu_set(C, NULL);
ED_editors_exit(C);
-
- /* just had return; here from r12991, this code could just get removed?*/
-#if 0
- if (wm == NULL) return;
- if (G.fileflags & G_FILE_NO_UI) return;
-
- /* we take apart the used screens from non-active window */
- for (win = wm->windows.first; win; win = win->next) {
- BLI_strncpy(win->screenname, win->screen->id.name, MAX_ID_NAME);
- if (win != wm->winactive) {
- BLI_remlink(&G_MAIN->screen, win->screen);
- //BLI_addtail(screenbase, win->screen);
- }
- }
-#endif
}
-static void wm_window_substitute_old(wmWindowManager *wm, wmWindow *oldwin, wmWindow *win)
+static void wm_window_substitute_old(wmWindowManager *oldwm, wmWindowManager *wm, wmWindow *oldwin, wmWindow *win)
{
win->ghostwin = oldwin->ghostwin;
- win->multisamples = oldwin->multisamples;
+ win->gwnctx = oldwin->gwnctx;
win->active = oldwin->active;
- if (win->active)
+ if (win->active) {
wm->winactive = win;
+ }
+ if (oldwm->windrawable == oldwin) {
+ oldwm->windrawable = NULL;
+ wm->windrawable = win;
+ }
if (!G.background) /* file loading in background mode still calls this */
GHOST_SetWindowUserData(win->ghostwin, win); /* pointer back */
oldwin->ghostwin = NULL;
- oldwin->multisamples = 0;
+ oldwin->gwnctx = NULL;
win->eventstate = oldwin->eventstate;
oldwin->eventstate = NULL;
@@ -218,102 +214,128 @@ static void wm_window_substitute_old(wmWindowManager *wm, wmWindow *oldwin, wmWi
win->posy = oldwin->posy;
}
-/* match old WM with new, 4 cases:
- * 1- no current wm, no read wm: make new default
- * 2- no current wm, but read wm: that's OK, do nothing
- * 3- current wm, but not in file: try match screen names
- * 4- current wm, and wm in file: try match ghostwin
- */
-
-static void wm_window_match_do(Main *bmain, bContext *C, ListBase *oldwmlist)
+static void wm_window_match_keep_current_wm(
+ const bContext *C, ListBase *current_wm_list,
+ const bool load_ui,
+ ListBase *r_new_wm_list)
{
- wmWindowManager *oldwm, *wm;
- wmWindow *oldwin, *win;
-
- /* cases 1 and 2 */
- if (BLI_listbase_is_empty(oldwmlist)) {
- if (bmain->wm.first) {
- /* nothing todo */
- }
- else {
- wm_add_default(C);
- }
- }
- else {
- /* cases 3 and 4 */
-
- /* we've read file without wm..., keep current one entirely alive */
- if (BLI_listbase_is_empty(&bmain->wm)) {
- bScreen *screen = NULL;
+ Main *bmain = CTX_data_main(C);
+ wmWindowManager *wm = current_wm_list->first;
+ bScreen *screen = NULL;
- /* when loading without UI, no matching needed */
- if (!(G.fileflags & G_FILE_NO_UI) && (screen = CTX_wm_screen(C))) {
+ /* match oldwm to new dbase, only old files */
+ wm->initialized &= ~WM_WINDOW_IS_INITIALIZED;
- /* match oldwm to new dbase, only old files */
- for (wm = oldwmlist->first; wm; wm = wm->id.next) {
+ /* when loading without UI, no matching needed */
+ if (load_ui && (screen = CTX_wm_screen(C))) {
+ for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ WorkSpace *workspace;
- for (win = wm->windows.first; win; win = win->next) {
- /* all windows get active screen from file */
- if (screen->winid == 0)
- win->screen = screen;
- else
- win->screen = ED_screen_duplicate(bmain, win, screen);
+ BKE_workspace_layout_find_global(bmain, screen, &workspace);
+ BKE_workspace_active_set(win->workspace_hook, workspace);
+ win->scene = CTX_data_scene(C);
- BLI_strncpy(win->screenname, win->screen->id.name + 2, sizeof(win->screenname));
- win->screen->winid = win->winid;
- }
- }
+ /* all windows get active screen from file */
+ if (screen->winid == 0) {
+ WM_window_set_active_screen(win, workspace, screen);
}
+ else {
+ WorkSpaceLayout *layout_old = WM_window_get_active_layout(win);
+ WorkSpaceLayout *layout_new = ED_workspace_layout_duplicate(bmain, workspace, layout_old, win);
- bmain->wm = *oldwmlist;
+ WM_window_set_active_layout(win, workspace, layout_new);
+ }
- /* screens were read from file! */
- ED_screens_initialize(bmain, bmain->wm.first);
+ bScreen *win_screen = WM_window_get_active_screen(win);
+ win_screen->winid = win->winid;
}
- else {
- bool has_match = false;
+ }
- /* what if old was 3, and loaded 1? */
- /* this code could move to setup_appdata */
- oldwm = oldwmlist->first;
- wm = bmain->wm.first;
+ *r_new_wm_list = *current_wm_list;
+}
- /* preserve key configurations in new wm, to preserve their keymaps */
- wm->keyconfigs = oldwm->keyconfigs;
- wm->addonconf = oldwm->addonconf;
- wm->defaultconf = oldwm->defaultconf;
- wm->userconf = oldwm->userconf;
+static void wm_window_match_replace_by_file_wm(
+ bContext *C, ListBase *current_wm_list, ListBase *readfile_wm_list,
+ ListBase *r_new_wm_list)
+{
+ wmWindowManager *oldwm = current_wm_list->first;
+ wmWindowManager *wm = readfile_wm_list->first; /* will become our new WM */
+ bool has_match = false;
- BLI_listbase_clear(&oldwm->keyconfigs);
- oldwm->addonconf = NULL;
- oldwm->defaultconf = NULL;
- oldwm->userconf = NULL;
+ /* this code could move to setup_appdata */
- /* ensure making new keymaps and set space types */
- wm->initialized = 0;
- wm->winactive = NULL;
+ /* preserve key configurations in new wm, to preserve their keymaps */
+ wm->keyconfigs = oldwm->keyconfigs;
+ wm->addonconf = oldwm->addonconf;
+ wm->defaultconf = oldwm->defaultconf;
+ wm->userconf = oldwm->userconf;
- /* only first wm in list has ghostwins */
- for (win = wm->windows.first; win; win = win->next) {
- for (oldwin = oldwm->windows.first; oldwin; oldwin = oldwin->next) {
+ BLI_listbase_clear(&oldwm->keyconfigs);
+ oldwm->addonconf = NULL;
+ oldwm->defaultconf = NULL;
+ oldwm->userconf = NULL;
- if (oldwin->winid == win->winid) {
- has_match = true;
+ /* ensure making new keymaps and set space types */
+ wm->initialized = 0;
+ wm->winactive = NULL;
- wm_window_substitute_old(wm, oldwin, win);
- }
- }
+ /* only first wm in list has ghostwins */
+ for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ for (wmWindow *oldwin = oldwm->windows.first; oldwin; oldwin = oldwin->next) {
+ if (oldwin->winid == win->winid) {
+ has_match = true;
+
+ wm_window_substitute_old(oldwm, wm, oldwin, win);
}
+ }
+ }
+ /* make sure at least one window is kept open so we don't lose the context, check T42303 */
+ if (!has_match) {
+ wm_window_substitute_old(oldwm, wm, oldwm->windows.first, wm->windows.first);
+ }
- /* make sure at least one window is kept open so we don't lose the context, check T42303 */
- if (!has_match) {
- oldwin = oldwm->windows.first;
- win = wm->windows.first;
+ wm_close_and_free_all(C, current_wm_list);
- wm_window_substitute_old(wm, oldwin, win);
- }
+ *r_new_wm_list = *readfile_wm_list;
+}
- wm_close_and_free_all(C, oldwmlist);
+/**
+ * Match old WM with new, 4 cases:
+ * 1) No current WM, no WM in file: Make new default.
+ * 2) No current WM, but WM in file: Keep current WM, do nothing else.
+ * 3) Current WM, but not in file: Keep current WM, update windows with screens from file.
+ * 4) Current WM, and WM in file: Try to keep current GHOST windows, use WM from file.
+ *
+ * \param r_new_wm_list: Return argument for the wm list to be used from now on.
+ */
+static void wm_window_match_do(
+ bContext *C,
+ ListBase *current_wm_list, ListBase *readfile_wm_list,
+ ListBase *r_new_wm_list)
+{
+ if (BLI_listbase_is_empty(current_wm_list)) {
+ /* case 1 */
+ if (BLI_listbase_is_empty(readfile_wm_list)) {
+ Main *bmain = CTX_data_main(C);
+ /* Neither current, no newly read file have a WM -> add the default one. */
+ wm_add_default(bmain, C);
+ *r_new_wm_list = bmain->wm;
+ }
+ /* case 2 */
+ else {
+ *r_new_wm_list = *readfile_wm_list;
+ }
+ }
+ else {
+ /* case 3 */
+ if (BLI_listbase_is_empty(readfile_wm_list)) {
+ /* We've read file without wm, keep current one entirely alive.
+ * Happens when reading pre 2.5 files (no WM back then) */
+ wm_window_match_keep_current_wm(C, current_wm_list, (G.fileflags & G_FILE_NO_UI) == 0, r_new_wm_list);
+ }
+ /* case 4 */
+ else {
+ wm_window_match_replace_by_file_wm(C, current_wm_list, readfile_wm_list, r_new_wm_list);
}
}
}
@@ -454,7 +476,6 @@ void wm_file_read_report(bContext *C, Main *bmain)
*/
static void wm_file_read_post(bContext *C, const bool is_startup_file, const bool use_userdef)
{
- Main *bmain = CTX_data_main(C);
bool addons_loaded = false;
wmWindowManager *wm = CTX_wm_manager(C);
@@ -465,8 +486,17 @@ static void wm_file_read_post(bContext *C, const bool is_startup_file, const boo
CTX_wm_window_set(C, wm->windows.first);
+ Main *bmain = CTX_data_main(C);
+ DEG_on_visible_update(bmain, true);
+
+ if (!is_startup_file) {
+ /* When starting up, the UI hasn't been fully initialised yet, and
+ * this call can trigger icon updates, causing a segfault due to a
+ * not-yet-initialised ghash for the icons. */
+ wm_event_do_depsgraph(C);
+ }
+
ED_editors_init(C);
- DAG_on_visible_update(bmain, true);
#ifdef WITH_PYTHON
if (is_startup_file) {
@@ -490,7 +520,7 @@ static void wm_file_read_post(bContext *C, const bool is_startup_file, const boo
addons_loaded = true;
}
#else
- UNUSED_VARS(use_userdef);
+ UNUSED_VARS(is_startup_file, use_userdef);
#endif /* WITH_PYTHON */
WM_operatortype_last_properties_clear_all();
@@ -499,16 +529,11 @@ static void wm_file_read_post(bContext *C, const bool is_startup_file, const boo
BLI_callback_exec(bmain, NULL, BLI_CB_EVT_VERSION_UPDATE);
BLI_callback_exec(bmain, NULL, BLI_CB_EVT_LOAD_POST);
- /* Would otherwise be handled by event loop.
- *
- * Disabled for startup file, since it causes problems when PyDrivers are used in the startup file.
- * While its possible state of startup file may be wrong,
- * in this case users nearly always load a file to replace the startup file. */
- if (G.background && (is_startup_file == false)) {
- BKE_scene_update_tagged(bmain->eval_ctx, bmain, CTX_data_scene(C));
- }
-
+#if 1
WM_event_add_notifier(C, NC_WM | ND_FILEREAD, NULL);
+#else
+ WM_msg_publish_static(CTX_wm_message_bus(C), WM_MSG_STATICTYPE_FILE_READ);
+#endif
/* report any errors.
* currently disabled if addons aren't yet loaded */
@@ -532,6 +557,9 @@ static void wm_file_read_post(bContext *C, const bool is_startup_file, const boo
* a blend file and do anything since the screen
* won't be set to a valid value again */
CTX_wm_window_set(C, NULL); /* exits queues */
+
+ /* Ensure tools are registered. */
+ WM_toolsystem_init(C);
}
}
@@ -589,7 +617,7 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports)
}
/* match the read WM with current WM */
- wm_window_match_do(bmain, C, &wmbase);
+ wm_window_match_do(C, &wmbase, &bmain->wm, &bmain->wm);
WM_check(C); /* opens window(s), checks keymaps */
if (retval == BKE_BLENDFILE_READ_OK_USERPREFS) {
@@ -607,6 +635,10 @@ bool WM_file_read(bContext *C, const char *filepath, ReportList *reports)
success = true;
}
+#if 0
+ else if (retval == BKE_READ_EXOTIC_OK_OTHER)
+ BKE_undo_write(C, "Import file");
+#endif
else if (retval == BKE_READ_EXOTIC_FAIL_OPEN) {
BKE_reportf(reports, RPT_ERROR, "Cannot read file '%s': %s", filepath,
errno ? strerror(errno) : TIP_("unable to open the file"));
@@ -858,22 +890,13 @@ int wm_homefile_read(
}
/* match the read WM with current WM */
- wm_window_match_do(bmain, C, &wmbase);
+ wm_window_match_do(C, &wmbase, &bmain->wm, &bmain->wm);
WM_check(C); /* opens window(s), checks keymaps */
bmain->name[0] = '\0';
- if (use_userdef) {
- /* When loading factory settings, the reset solid OpenGL lights need to be applied. */
- if (!G.background) {
- GPU_default_lights();
- }
- }
-
/* start with save preference untitled.blend */
G.save_over = 0;
- /* disable auto-play in startup.blend... */
- G.fileflags &= ~G_FILE_AUTOPLAY;
wm_file_read_post(C, true, use_userdef);
@@ -1006,7 +1029,7 @@ static void wm_history_file_update(void)
/* screen can be NULL */
-static ImBuf *blend_file_thumb(Main *bmain, Scene *scene, bScreen *screen, BlendThumbnail **thumb_pt)
+static ImBuf *blend_file_thumb(const bContext *C, Scene *scene, bScreen *screen, BlendThumbnail **thumb_pt)
{
/* will be scaled down, but gives some nice oversampling */
ImBuf *ibuf;
@@ -1041,19 +1064,21 @@ static ImBuf *blend_file_thumb(Main *bmain, Scene *scene, bScreen *screen, Blend
}
/* gets scaled to BLEN_THUMB_SIZE */
+ Depsgraph *depsgraph = CTX_data_depsgraph(C);
+
if (scene->camera) {
ibuf = ED_view3d_draw_offscreen_imbuf_simple(
- bmain, scene, scene->camera,
+ depsgraph, scene, OB_SOLID, scene->camera,
BLEN_THUMB_SIZE * 2, BLEN_THUMB_SIZE * 2,
- IB_rect, V3D_OFSDRAW_NONE, OB_SOLID, R_ALPHAPREMUL, 0, NULL,
- NULL, NULL, err_out);
+ IB_rect, V3D_OFSDRAW_NONE, R_ALPHAPREMUL, 0, NULL,
+ NULL, err_out);
}
else {
ibuf = ED_view3d_draw_offscreen_imbuf(
- bmain, scene, v3d, ar,
+ depsgraph, scene, OB_SOLID, v3d, ar,
BLEN_THUMB_SIZE * 2, BLEN_THUMB_SIZE * 2,
IB_rect, V3D_OFSDRAW_NONE, R_ALPHAPREMUL, 0, NULL,
- NULL, NULL, err_out);
+ NULL, err_out);
}
if (ibuf) {
@@ -1147,7 +1172,7 @@ static int wm_file_write(bContext *C, const char *filepath, int fileflags, Repor
/* Main now can store a .blend thumbnail, usefull for background mode or thumbnail customization. */
main_thumb = thumb = bmain->blen_thumb;
if ((U.flag & USER_SAVE_PREVIEWS) && BLI_thread_is_main()) {
- ibuf_thumb = blend_file_thumb(bmain, CTX_data_scene(C), CTX_wm_screen(C), &thumb);
+ ibuf_thumb = blend_file_thumb(C, CTX_data_scene(C), CTX_wm_screen(C), &thumb);
}
/* operator now handles overwrite checks */
@@ -1183,7 +1208,6 @@ static int wm_file_write(bContext *C, const char *filepath, int fileflags, Repor
}
SET_FLAG_FROM_TEST(G.fileflags, fileflags & G_FILE_COMPRESS, G_FILE_COMPRESS);
- SET_FLAG_FROM_TEST(G.fileflags, fileflags & G_FILE_AUTOPLAY, G_FILE_AUTOPLAY);
/* prevent background mode scripts from clobbering history */
if (do_history) {
@@ -1291,7 +1315,7 @@ void wm_autosave_timer(const bContext *C, wmWindowManager *wm, wmTimer *UNUSED(w
}
else {
/* save as regular blend file */
- int fileflags = G.fileflags & ~(G_FILE_COMPRESS | G_FILE_AUTOPLAY | G_FILE_HISTORY);
+ int fileflags = G.fileflags & ~(G_FILE_COMPRESS | G_FILE_HISTORY);
ED_editors_flush_edits(C, false);
@@ -1406,7 +1430,7 @@ static int wm_homefile_write_exec(bContext *C, wmOperator *op)
BLI_callback_exec(bmain, NULL, BLI_CB_EVT_SAVE_PRE);
/* check current window and close it if temp */
- if (win && win->screen->temp)
+ if (win && WM_window_is_temp_screen(win))
wm_window_close(C, wm, win);
/* update keymaps in user preferences */
@@ -1419,7 +1443,7 @@ static int wm_homefile_write_exec(bContext *C, wmOperator *op)
ED_editors_flush_edits(C, false);
/* force save as regular blend file */
- fileflags = G.fileflags & ~(G_FILE_COMPRESS | G_FILE_AUTOPLAY | G_FILE_HISTORY);
+ fileflags = G.fileflags & ~(G_FILE_COMPRESS | G_FILE_HISTORY);
if (BLO_write_file(bmain, filepath, fileflags | G_FILE_USERPREFS, op->reports, NULL) == 0) {
printf("fail\n");
@@ -1553,6 +1577,42 @@ void WM_OT_save_userpref(wmOperatorType *ot)
ot->exec = wm_userpref_write_exec;
}
+static int wm_workspace_configuration_file_write_exec(bContext *C, wmOperator *op)
+{
+ Main *bmain = CTX_data_main(C);
+ char filepath[FILE_MAX];
+
+ const char *app_template = U.app_template[0] ? U.app_template : NULL;
+ const char * const cfgdir = BKE_appdir_folder_id_create(BLENDER_USER_CONFIG, app_template);
+ if (cfgdir == NULL) {
+ BKE_report(op->reports, RPT_ERROR, "Unable to create workspace configuration file path");
+ return OPERATOR_CANCELLED;
+ }
+
+ BLI_path_join(filepath, sizeof(filepath), cfgdir, BLENDER_WORKSPACES_FILE, NULL);
+ printf("trying to save workspace configuration file at %s ", filepath);
+
+ if (BKE_blendfile_workspace_config_write(bmain, filepath, op->reports) != 0) {
+ printf("ok\n");
+ return OPERATOR_FINISHED;
+ }
+ else {
+ printf("fail\n");
+ }
+
+ return OPERATOR_CANCELLED;
+}
+
+void WM_OT_save_workspace_file(wmOperatorType *ot)
+{
+ ot->name = "Save Workspace Configuration";
+ ot->idname = "WM_OT_save_workspace_file";
+ ot->description = "Save workspaces of the current file as part of the user configuration";
+
+ ot->invoke = WM_operator_confirm;
+ ot->exec = wm_workspace_configuration_file_write_exec;
+}
+
static int wm_history_file_read_exec(bContext *UNUSED(C), wmOperator *UNUSED(op))
{
ED_file_read_bookmarks();
@@ -2092,9 +2152,11 @@ static int wm_save_as_mainfile_exec(bContext *C, wmOperator *op)
WM_event_add_notifier(C, NC_WM | ND_FILESAVE, NULL);
+#if 0 /* XXX: Remove? This is not currently defined as a valid property */
if (RNA_boolean_get(op->ptr, "exit")) {
wm_exit_schedule_delayed(C);
}
+#endif
return OPERATOR_FINISHED;
}
diff --git a/source/blender/windowmanager/intern/wm_files_link.c b/source/blender/windowmanager/intern/wm_files_link.c
index 72973d3de56..903795d6943 100644
--- a/source/blender/windowmanager/intern/wm_files_link.c
+++ b/source/blender/windowmanager/intern/wm_files_link.c
@@ -59,7 +59,7 @@
#include "BLO_readfile.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
+#include "BKE_layer.h"
#include "BKE_library.h"
#include "BKE_library_remap.h"
#include "BKE_global.h"
@@ -69,13 +69,13 @@
#include "BKE_idcode.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
#include "IMB_colormanagement.h"
#include "ED_screen.h"
-#include "GPU_material.h"
-
#include "RNA_access.h"
#include "RNA_define.h"
@@ -131,13 +131,13 @@ static short wm_link_append_flag(wmOperator *op)
if (RNA_boolean_get(op->ptr, "autoselect"))
flag |= FILE_AUTOSELECT;
- if (RNA_boolean_get(op->ptr, "active_layer"))
- flag |= FILE_ACTIVELAY;
+ if (RNA_boolean_get(op->ptr, "active_collection"))
+ flag |= FILE_ACTIVE_COLLECTION;
if ((prop = RNA_struct_find_property(op->ptr, "relative_path")) && RNA_property_boolean_get(op->ptr, prop))
flag |= FILE_RELPATH;
if (RNA_boolean_get(op->ptr, "link"))
flag |= FILE_LINK;
- if (RNA_boolean_get(op->ptr, "instance_groups"))
+ if (RNA_boolean_get(op->ptr, "instance_collections"))
flag |= FILE_GROUP_INSTANCE;
return flag;
@@ -211,7 +211,8 @@ static WMLinkAppendDataItem *wm_link_append_data_item_add(
return item;
}
-static void wm_link_do(WMLinkAppendData *lapp_data, ReportList *reports, Main *bmain, Scene *scene, View3D *v3d)
+static void wm_link_do(
+ WMLinkAppendData *lapp_data, ReportList *reports, Main *bmain, Scene *scene, ViewLayer *view_layer)
{
Main *mainl;
BlendHandle *bh;
@@ -258,7 +259,7 @@ static void wm_link_do(WMLinkAppendData *lapp_data, ReportList *reports, Main *b
continue;
}
- new_id = BLO_library_link_named_part_ex(mainl, &bh, item->idcode, item->name, flag, scene, v3d);
+ new_id = BLO_library_link_named_part_ex(mainl, &bh, item->idcode, item->name, flag, bmain, scene, view_layer);
if (new_id) {
/* If the link is successful, clear item's libs 'todo' flags.
@@ -268,15 +269,50 @@ static void wm_link_do(WMLinkAppendData *lapp_data, ReportList *reports, Main *b
}
}
- BLO_library_link_end(mainl, &bh, flag, scene, v3d);
+ BLO_library_link_end(mainl, &bh, flag, bmain, scene, view_layer);
BLO_blendhandle_close(bh);
}
}
+/**
+ * Check if an item defined by \a name and \a group can be appended/linked.
+ *
+ * \param reports: Optionally report an error when an item can't be appended/linked.
+ */
+static bool wm_link_append_item_poll(
+ ReportList *reports, const char *path, const char *group, const char *name, const bool do_append)
+{
+ short idcode;
+
+ if (!group || !name) {
+ printf("skipping %s\n", path);
+ return false;
+ }
+
+ idcode = BKE_idcode_from_name(group);
+
+ /* XXX For now, we do a nasty exception for workspace, forbid linking them.
+ * Not nice, ultimately should be solved! */
+ if (!BKE_idcode_is_linkable(idcode) && (do_append || idcode != ID_WS)) {
+ if (reports) {
+ if (do_append) {
+ BKE_reportf(reports, RPT_ERROR_INVALID_INPUT, "Can't append data-block '%s' of type '%s'", name, group);
+ }
+ else {
+ BKE_reportf(reports, RPT_ERROR_INVALID_INPUT, "Can't link data-block '%s' of type '%s'", name, group);
+ }
+ }
+ return false;
+ }
+
+ return true;
+}
+
static int wm_link_append_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
PropertyRNA *prop;
WMLinkAppendData *lapp_data;
char path[FILE_MAX_LIBEXTRA], root[FILE_MAXDIR], libname[FILE_MAX_LIBEXTRA], relname[FILE_MAX];
@@ -319,6 +355,7 @@ static int wm_link_append_exec(bContext *C, wmOperator *op)
}
short flag = wm_link_append_flag(op);
+ const bool do_append = (flag & FILE_LINK) == 0;
/* sanity checks for flag */
if (scene && scene->id.lib) {
@@ -332,8 +369,8 @@ static int wm_link_append_exec(bContext *C, wmOperator *op)
/* from here down, no error returns */
- if (scene && RNA_boolean_get(op->ptr, "autoselect")) {
- BKE_scene_base_deselect_all(scene);
+ if (view_layer && RNA_boolean_get(op->ptr, "autoselect")) {
+ BKE_view_layer_base_deselect_all(view_layer);
}
/* tag everything, all untagged data can be made local
@@ -356,7 +393,7 @@ static int wm_link_append_exec(bContext *C, wmOperator *op)
BLI_join_dirfile(path, sizeof(path), root, relname);
if (BLO_library_path_explode(path, libname, &group, &name)) {
- if (!group || !name) {
+ if (!wm_link_append_item_poll(NULL, path, group, name, do_append)) {
continue;
}
@@ -377,8 +414,8 @@ static int wm_link_append_exec(bContext *C, wmOperator *op)
if (BLO_library_path_explode(path, libname, &group, &name)) {
WMLinkAppendDataItem *item;
- if (!group || !name) {
- printf("skipping %s\n", path);
+
+ if (!wm_link_append_item_poll(op->reports, path, group, name, do_append)) {
continue;
}
@@ -409,7 +446,7 @@ static int wm_link_append_exec(bContext *C, wmOperator *op)
/* XXX We'd need re-entrant locking on Main for this to work... */
/* BKE_main_lock(bmain); */
- wm_link_do(lapp_data, op->reports, bmain, scene, CTX_wm_view3d(C));
+ wm_link_do(lapp_data, op->reports, bmain, scene, view_layer);
/* BKE_main_unlock(bmain); */
@@ -418,7 +455,7 @@ static int wm_link_append_exec(bContext *C, wmOperator *op)
IMB_colormanagement_check_file_config(bmain);
/* append, rather than linking */
- if ((flag & FILE_LINK) == 0) {
+ if (do_append) {
const bool set_fake = RNA_boolean_get(op->ptr, "set_fake");
const bool use_recursive = RNA_boolean_get(op->ptr, "use_recursive");
@@ -449,13 +486,17 @@ static int wm_link_append_exec(bContext *C, wmOperator *op)
* link into other scenes from this blend file */
BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false);
- /* recreate dependency graph to include new objects */
- if (scene) {
- DAG_scene_relations_rebuild(bmain, scene);
- }
+ /* TODO(sergey): Use proper flag for tagging here. */
- /* free gpu materials, some materials depend on existing objects, such as lamps so freeing correctly refreshes */
- GPU_materials_free(bmain);
+ /* TODO (dalai): Temporary solution!
+ * Ideally we only need to tag the new objects themselves, not the scene. This way we'll avoid flush of
+ * collection properties to all objects and limit update to the particular object only.
+ * But afraid first we need to change collection evaluation in DEG according to depsgraph manifesto.
+ */
+ DEG_id_tag_update(&scene->id, 0);
+
+ /* recreate dependency graph to include new objects */
+ DEG_relations_tag_update(bmain);
/* XXX TODO: align G.lib with other directory storage (like last opened image etc...) */
BLI_strncpy(G.lib, root, FILE_MAX);
@@ -477,11 +518,11 @@ static void wm_link_append_properties_common(wmOperatorType *ot, bool is_link)
prop = RNA_def_boolean(ot->srna, "autoselect", true,
"Select", "Select new objects");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
- prop = RNA_def_boolean(ot->srna, "active_layer", true,
- "Active Layer", "Put new objects on the active layer");
+ prop = RNA_def_boolean(ot->srna, "active_collection", true,
+ "Active Collection", "Put new objects on the active collection");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
- prop = RNA_def_boolean(ot->srna, "instance_groups", is_link,
- "Instance Groups", "Create Dupli-Group instances for each group");
+ prop = RNA_def_boolean(ot->srna, "instance_collections", is_link,
+ "Instance Collections", "Create instances for collections, rather than adding them directly to the scene");
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
@@ -558,7 +599,7 @@ static int wm_lib_relocate_invoke(bContext *C, wmOperator *op, const wmEvent *UN
}
static void lib_relocate_do(
- Main *bmain, Scene *scene,
+ Main *bmain,
Library *library, WMLinkAppendData *lapp_data, ReportList *reports, const bool do_reload)
{
ListBase *lbarray[MAX_LIBARRAY];
@@ -748,10 +789,7 @@ static void lib_relocate_do(
BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false);
/* recreate dependency graph to include new objects */
- DAG_scene_relations_rebuild(bmain, scene);
-
- /* free gpu materials, some materials depend on existing objects, such as lamps so freeing correctly refreshes */
- GPU_materials_free(bmain);
+ DEG_relations_tag_update(bmain);
}
void WM_lib_reload(Library *lib, bContext *C, ReportList *reports)
@@ -771,7 +809,7 @@ void WM_lib_reload(Library *lib, bContext *C, ReportList *reports)
wm_link_append_data_library_add(lapp_data, lib->filepath);
- lib_relocate_do(CTX_data_main(C), CTX_data_scene(C), lib, lapp_data, reports, true);
+ lib_relocate_do(CTX_data_main(C), lib, lapp_data, reports, true);
wm_link_append_data_free(lapp_data);
@@ -788,7 +826,6 @@ static int wm_lib_relocate_exec_do(bContext *C, wmOperator *op, bool do_reload)
if (lib) {
Main *bmain = CTX_data_main(C);
- Scene *scene = CTX_data_scene(C);
PropertyRNA *prop;
WMLinkAppendData *lapp_data;
@@ -882,7 +919,7 @@ static int wm_lib_relocate_exec_do(bContext *C, wmOperator *op, bool do_reload)
lapp_data->flag |= BLO_LIBLINK_USE_PLACEHOLDERS | BLO_LIBLINK_FORCE_INDIRECT;
}
- lib_relocate_do(bmain, scene, lib, lapp_data, op->reports, do_reload);
+ lib_relocate_do(bmain, lib, lapp_data, op->reports, do_reload);
wm_link_append_data_free(lapp_data);
diff --git a/source/blender/windowmanager/intern/wm_gesture.c b/source/blender/windowmanager/intern/wm_gesture.c
index a0a38c5bc3f..4366013084c 100644
--- a/source/blender/windowmanager/intern/wm_gesture.c
+++ b/source/blender/windowmanager/intern/wm_gesture.c
@@ -45,15 +45,14 @@
#include "BKE_context.h"
-
#include "WM_api.h"
#include "WM_types.h"
#include "wm.h"
-#include "wm_subwindow.h"
#include "wm_draw.h"
-#include "GPU_basic_shader.h"
+#include "GPU_immediate.h"
+#include "GPU_immediate_util.h"
#include "BIF_glutil.h"
@@ -64,40 +63,37 @@ wmGesture *WM_gesture_new(bContext *C, const wmEvent *event, int type)
wmGesture *gesture = MEM_callocN(sizeof(wmGesture), "new gesture");
wmWindow *window = CTX_wm_window(C);
ARegion *ar = CTX_wm_region(C);
- int sx, sy;
BLI_addtail(&window->gesture, gesture);
gesture->type = type;
gesture->event_type = event->type;
- gesture->swinid = ar->swinid; /* means only in area-region context! */
+ gesture->winrct = ar->winrct;
gesture->userdata_free = true; /* Free if userdata is set. */
gesture->modal_state = GESTURE_MODAL_NOP;
- wm_subwindow_origin_get(window, gesture->swinid, &sx, &sy);
-
if (ELEM(type, WM_GESTURE_RECT, WM_GESTURE_CROSS_RECT, WM_GESTURE_TWEAK,
WM_GESTURE_CIRCLE, WM_GESTURE_STRAIGHTLINE))
{
rcti *rect = MEM_callocN(sizeof(rcti), "gesture rect new");
gesture->customdata = rect;
- rect->xmin = event->x - sx;
- rect->ymin = event->y - sy;
+ rect->xmin = event->x - gesture->winrct.xmin;
+ rect->ymin = event->y - gesture->winrct.ymin;
if (type == WM_GESTURE_CIRCLE) {
/* caller is responsible for initializing 'xmax' to radius. */
}
else {
- rect->xmax = event->x - sx;
- rect->ymax = event->y - sy;
+ rect->xmax = event->x - gesture->winrct.xmin;
+ rect->ymax = event->y - gesture->winrct.ymin;
}
}
else if (ELEM(type, WM_GESTURE_LINES, WM_GESTURE_LASSO)) {
short *lasso;
gesture->points_alloc = 1024;
gesture->customdata = lasso = MEM_mallocN(sizeof(short[2]) * gesture->points_alloc, "lasso points");
- lasso[0] = event->x - sx;
- lasso[1] = event->y - sy;
+ lasso[0] = event->x - gesture->winrct.xmin;
+ lasso[1] = event->y - gesture->winrct.ymin;
gesture->points = 1;
}
@@ -166,69 +162,99 @@ int wm_gesture_evaluate(wmGesture *gesture)
/* ******************* gesture draw ******************* */
-static void wm_gesture_draw_rect(wmGesture *gt)
+static void wm_gesture_draw_line(wmGesture *gt)
{
rcti *rect = (rcti *)gt->customdata;
- glEnable(GL_BLEND);
- glColor4f(1.0, 1.0, 1.0, 0.05);
- glBegin(GL_QUADS);
- glVertex2s(rect->xmax, rect->ymin);
- glVertex2s(rect->xmax, rect->ymax);
- glVertex2s(rect->xmin, rect->ymax);
- glVertex2s(rect->xmin, rect->ymin);
- glEnd();
- glDisable(GL_BLEND);
+ uint shdr_pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
+
+ float viewport_size[4];
+ glGetFloatv(GL_VIEWPORT, viewport_size);
+ immUniform2f("viewport_size", viewport_size[2], viewport_size[3]);
- GPU_basic_shader_bind(GPU_SHADER_LINE | GPU_SHADER_STIPPLE | GPU_SHADER_USE_COLOR);
- glColor3ub(96, 96, 96);
- GPU_basic_shader_line_stipple(1, 0xCCCC);
- sdrawbox(rect->xmin, rect->ymin, rect->xmax, rect->ymax);
- glColor3ub(255, 255, 255);
- GPU_basic_shader_line_stipple(1, 0x3333);
- sdrawbox(rect->xmin, rect->ymin, rect->xmax, rect->ymax);
- GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
+ immUniform1i("colors_len", 2); /* "advanced" mode */
+ immUniformArray4fv("colors", (float *)(float[][4]){{0.4f, 0.4f, 0.4f, 1.0f}, {1.0f, 1.0f, 1.0f, 1.0f}}, 2);
+ immUniform1f("dash_width", 8.0f);
+
+ float xmin = (float)rect->xmin;
+ float ymin = (float)rect->ymin;
+
+ immBegin(GWN_PRIM_LINES, 2);
+ immVertex2f(shdr_pos, xmin, ymin);
+ immVertex2f(shdr_pos, (float)rect->xmax, (float)rect->ymax);
+ immEnd();
+
+ immUnbindProgram();
}
-static void wm_gesture_draw_line(wmGesture *gt)
+static void wm_gesture_draw_rect(wmGesture *gt)
{
rcti *rect = (rcti *)gt->customdata;
- GPU_basic_shader_bind(GPU_SHADER_LINE | GPU_SHADER_STIPPLE);
- glColor3ub(96, 96, 96);
- GPU_basic_shader_line_stipple(1, 0xAAAA);
- sdrawline(rect->xmin, rect->ymin, rect->xmax, rect->ymax);
- glColor3ub(255, 255, 255);
- GPU_basic_shader_line_stipple(1, 0x5555);
- sdrawline(rect->xmin, rect->ymin, rect->xmax, rect->ymax);
+ uint shdr_pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_I32, 2, GWN_FETCH_INT_TO_FLOAT);
+
+ glEnable(GL_BLEND);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformColor4f(1.0f, 1.0f, 1.0f, 0.05f);
- GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
+ immRecti(shdr_pos, rect->xmin, rect->ymin, rect->xmax, rect->ymax);
+ immUnbindProgram();
+
+ glDisable(GL_BLEND);
+
+ shdr_pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
+
+ float viewport_size[4];
+ glGetFloatv(GL_VIEWPORT, viewport_size);
+ immUniform2f("viewport_size", viewport_size[2], viewport_size[3]);
+
+ immUniform1i("colors_len", 2); /* "advanced" mode */
+ immUniformArray4fv("colors", (float *)(float[][4]){{0.4f, 0.4f, 0.4f, 1.0f}, {1.0f, 1.0f, 1.0f, 1.0f}}, 2);
+ immUniform1f("dash_width", 8.0f);
+
+ imm_draw_box_wire_2d(shdr_pos, (float)rect->xmin, (float)rect->ymin, (float)rect->xmax, (float)rect->ymax);
+
+ immUnbindProgram();
+
+ // wm_gesture_draw_line(gt); // draws a diagonal line in the lined box to test wm_gesture_draw_line
}
static void wm_gesture_draw_circle(wmGesture *gt)
{
rcti *rect = (rcti *)gt->customdata;
- glTranslatef((float)rect->xmin, (float)rect->ymin, 0.0f);
-
glEnable(GL_BLEND);
- glColor4f(1.0, 1.0, 1.0, 0.05);
- glutil_draw_filled_arc(0.0, M_PI * 2.0, rect->xmax, 40);
+
+ const uint shdr_pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+
+ immUniformColor4f(1.0f, 1.0f, 1.0f, 0.05f);
+ imm_draw_circle_fill_2d(shdr_pos, (float)rect->xmin, (float)rect->ymin, (float)rect->xmax, 40);
+
+ immUnbindProgram();
+
glDisable(GL_BLEND);
- // for USE_GLSL works bad because of no relation between lines
- GPU_basic_shader_bind(GPU_SHADER_LINE | GPU_SHADER_STIPPLE | GPU_SHADER_USE_COLOR);
- glColor3ub(96, 96, 96);
- GPU_basic_shader_line_stipple(1, 0xAAAA);
- glutil_draw_lined_arc(0.0, M_PI * 2.0, rect->xmax, 40);
- glColor3ub(255, 255, 255);
- GPU_basic_shader_line_stipple(1, 0x5555);
- glutil_draw_lined_arc(0.0, M_PI * 2.0, rect->xmax, 40);
+ immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
+
+ float viewport_size[4];
+ glGetFloatv(GL_VIEWPORT, viewport_size);
+ immUniform2f("viewport_size", viewport_size[2], viewport_size[3]);
- GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
- glTranslatef(-rect->xmin, -rect->ymin, 0.0f);
+ immUniform1i("colors_len", 2); /* "advanced" mode */
+ immUniformArray4fv("colors", (float *)(float[][4]){{0.4f, 0.4f, 0.4f, 1.0f}, {1.0f, 1.0f, 1.0f, 1.0f}}, 2);
+ immUniform1f("dash_width", 4.0f);
+ imm_draw_circle_wire_2d(shdr_pos, (float)rect->xmin, (float)rect->ymin, (float)rect->xmax, 40);
+
+ immUnbindProgram();
}
struct LassoFillData {
@@ -243,14 +269,14 @@ static void draw_filled_lasso_px_cb(int x, int x_end, int y, void *user_data)
memset(col, 0x10, x_end - x);
}
-static void draw_filled_lasso(wmWindow *win, wmGesture *gt)
+static void draw_filled_lasso(wmGesture *gt)
{
const short *lasso = (short *)gt->customdata;
const int tot = gt->points;
int (*moves)[2] = MEM_mallocN(sizeof(*moves) * (tot + 1), __func__);
int i;
rcti rect;
- rcti rect_win;
+ float red[4] = {1.0f, 0.0f, 0.0f, 0.0f};
for (i = 0; i < tot; i++, lasso += 2) {
moves[i][0] = lasso[0];
@@ -259,10 +285,9 @@ static void draw_filled_lasso(wmWindow *win, wmGesture *gt)
BLI_lasso_boundbox(&rect, (const int (*)[2])moves, tot);
- wm_subwindow_rect_get(win, gt->swinid, &rect_win);
- BLI_rcti_translate(&rect, rect_win.xmin, rect_win.ymin);
- BLI_rcti_isect(&rect_win, &rect, &rect);
- BLI_rcti_translate(&rect, -rect_win.xmin, -rect_win.ymin);
+ BLI_rcti_translate(&rect, gt->winrct.xmin, gt->winrct.ymin);
+ BLI_rcti_isect(&gt->winrct, &rect, &rect);
+ BLI_rcti_translate(&rect, -gt->winrct.xmin, -gt->winrct.ymin);
/* highly unlikely this will fail, but could crash if (tot == 0) */
if (BLI_rcti_is_empty(&rect) == false) {
@@ -276,66 +301,72 @@ static void draw_filled_lasso(wmWindow *win, wmGesture *gt)
(const int (*)[2])moves, tot,
draw_filled_lasso_px_cb, &lasso_fill_data);
- glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+ /* Additive Blending */
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_ONE, GL_ONE);
- glColor4f(1, 1, 1, 1);
- glPixelTransferf(GL_RED_BIAS, 1);
- glPixelTransferf(GL_GREEN_BIAS, 1);
- glPixelTransferf(GL_BLUE_BIAS, 1);
+ GLint unpack_alignment;
+ glGetIntegerv(GL_UNPACK_ALIGNMENT, &unpack_alignment);
- GPU_basic_shader_bind(GPU_SHADER_TEXTURE_2D | GPU_SHADER_USE_COLOR);
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
- glEnable(GL_BLEND);
- glaDrawPixelsTex(rect.xmin, rect.ymin, w, h, GL_ALPHA, GL_UNSIGNED_BYTE, GL_NEAREST, pixel_buf);
- glDisable(GL_BLEND);
+ IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_SHUFFLE_COLOR);
+ GPU_shader_bind(state.shader);
+ GPU_shader_uniform_vector(state.shader, GPU_shader_get_uniform(state.shader, "shuffle"), 4, 1, red);
- GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
+ immDrawPixelsTex(&state, rect.xmin, rect.ymin, w, h, GL_RED, GL_UNSIGNED_BYTE, GL_NEAREST, pixel_buf, 1.0f, 1.0f, NULL);
- glPixelTransferf(GL_RED_BIAS, 0);
- glPixelTransferf(GL_GREEN_BIAS, 0);
- glPixelTransferf(GL_BLUE_BIAS, 0);
+ GPU_shader_unbind();
- glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
+ glPixelStorei(GL_UNPACK_ALIGNMENT, unpack_alignment);
MEM_freeN(pixel_buf);
+
+ glDisable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
MEM_freeN(moves);
}
-static void wm_gesture_draw_lasso(wmWindow *win, wmGesture *gt, bool filled)
+static void wm_gesture_draw_lasso(wmGesture *gt, bool filled)
{
const short *lasso = (short *)gt->customdata;
int i;
if (filled) {
- draw_filled_lasso(win, gt);
+ draw_filled_lasso(gt);
+ }
+
+ const int numverts = gt->points;
+
+ /* Nothing to draw, do early output. */
+ if (numverts < 2) {
+ return;
+ }
+
+ const uint shdr_pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
+
+ float viewport_size[4];
+ glGetFloatv(GL_VIEWPORT, viewport_size);
+ immUniform2f("viewport_size", viewport_size[2], viewport_size[3]);
+
+ immUniform1i("colors_len", 2); /* "advanced" mode */
+ immUniformArray4fv("colors", (float *)(float[][4]){{0.4f, 0.4f, 0.4f, 1.0f}, {1.0f, 1.0f, 1.0f, 1.0f}}, 2);
+ immUniform1f("dash_width", 2.0f);
+
+ immBegin((gt->type == WM_GESTURE_LASSO) ? GWN_PRIM_LINE_LOOP : GWN_PRIM_LINE_STRIP, numverts);
+
+ for (i = 0; i < gt->points; i++, lasso += 2) {
+ immVertex2f(shdr_pos, (float)lasso[0], (float)lasso[1]);
}
- // for USE_GLSL can't check this yet
- GPU_basic_shader_bind(GPU_SHADER_LINE | GPU_SHADER_STIPPLE | GPU_SHADER_USE_COLOR);
- glColor3ub(96, 96, 96);
- GPU_basic_shader_line_stipple(1, 0xAAAA);
- glBegin(GL_LINE_STRIP);
- for (i = 0; i < gt->points; i++, lasso += 2)
- glVertex2sv(lasso);
- if (gt->type == WM_GESTURE_LASSO)
- glVertex2sv((short *)gt->customdata);
- glEnd();
-
- glColor3ub(255, 255, 255);
- GPU_basic_shader_line_stipple(1, 0x5555);
- glBegin(GL_LINE_STRIP);
- lasso = (short *)gt->customdata;
- for (i = 0; i < gt->points; i++, lasso += 2)
- glVertex2sv(lasso);
- if (gt->type == WM_GESTURE_LASSO)
- glVertex2sv((short *)gt->customdata);
- glEnd();
-
- GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
+ immEnd();
+ immUnbindProgram();
}
static void wm_gesture_draw_cross(wmWindow *win, wmGesture *gt)
@@ -344,17 +375,41 @@ static void wm_gesture_draw_cross(wmWindow *win, wmGesture *gt)
const int winsize_x = WM_window_pixels_x(win);
const int winsize_y = WM_window_pixels_y(win);
- GPU_basic_shader_bind(GPU_SHADER_LINE | GPU_SHADER_STIPPLE | GPU_SHADER_USE_COLOR);
- glColor3ub(96, 96, 96);
- GPU_basic_shader_line_stipple(1, 0xCCCC);
- sdrawline(rect->xmin - winsize_x, rect->ymin, rect->xmin + winsize_x, rect->ymin);
- sdrawline(rect->xmin, rect->ymin - winsize_y, rect->xmin, rect->ymin + winsize_y);
-
- glColor3ub(255, 255, 255);
- GPU_basic_shader_line_stipple(1, 0x3333);
- sdrawline(rect->xmin - winsize_x, rect->ymin, rect->xmin + winsize_x, rect->ymin);
- sdrawline(rect->xmin, rect->ymin - winsize_y, rect->xmin, rect->ymin + winsize_y);
- GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
+ float x1, x2, y1, y2;
+
+ const uint shdr_pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_LINE_DASHED_UNIFORM_COLOR);
+
+ float viewport_size[4];
+ glGetFloatv(GL_VIEWPORT, viewport_size);
+ immUniform2f("viewport_size", viewport_size[2], viewport_size[3]);
+
+ immUniform1i("colors_len", 2); /* "advanced" mode */
+ immUniformArray4fv("colors", (float *)(float[][4]){{0.4f, 0.4f, 0.4f, 1.0f}, {1.0f, 1.0f, 1.0f, 1.0f}}, 2);
+ immUniform1f("dash_width", 8.0f);
+
+ immBegin(GWN_PRIM_LINES, 4);
+
+ x1 = (float)(rect->xmin - winsize_x);
+ y1 = (float)rect->ymin;
+ x2 = (float)(rect->xmin + winsize_x);
+ y2 = y1;
+
+ immVertex2f(shdr_pos, x1, y1);
+ immVertex2f(shdr_pos, x2, y2);
+
+ x1 = (float)rect->xmin;
+ y1 = (float)(rect->ymin - winsize_y);
+ x2 = x1;
+ y2 = (float)(rect->ymin + winsize_y);
+
+ immVertex2f(shdr_pos, x1, y1);
+ immVertex2f(shdr_pos, x2, y2);
+
+ immEnd();
+
+ immUnbindProgram();
}
/* called in wm_draw.c */
@@ -362,10 +417,10 @@ void wm_gesture_draw(wmWindow *win)
{
wmGesture *gt = (wmGesture *)win->gesture.first;
- GPU_basic_shader_line_width(1);
+ glLineWidth(1.0f);
for (; gt; gt = gt->next) {
/* all in subwindow space */
- wmSubWindowSet(win, gt->swinid);
+ wmViewport(&gt->winrct);
if (gt->type == WM_GESTURE_RECT)
wm_gesture_draw_rect(gt);
@@ -382,9 +437,9 @@ void wm_gesture_draw(wmWindow *win)
}
}
else if (gt->type == WM_GESTURE_LINES)
- wm_gesture_draw_lasso(win, gt, false);
+ wm_gesture_draw_lasso(gt, false);
else if (gt->type == WM_GESTURE_LASSO)
- wm_gesture_draw_lasso(win, gt, true);
+ wm_gesture_draw_lasso(gt, true);
else if (gt->type == WM_GESTURE_STRAIGHTLINE)
wm_gesture_draw_line(gt);
}
@@ -392,12 +447,8 @@ void wm_gesture_draw(wmWindow *win)
void wm_gesture_tag_redraw(bContext *C)
{
- wmWindow *win = CTX_wm_window(C);
bScreen *screen = CTX_wm_screen(C);
- ARegion *ar = CTX_wm_region(C);
if (screen)
screen->do_draw_gesture = true;
-
- wm_tag_redraw_overlay(win, ar);
}
diff --git a/source/blender/windowmanager/intern/wm_gesture_ops.c b/source/blender/windowmanager/intern/wm_gesture_ops.c
index a554727cacd..01184f47920 100644
--- a/source/blender/windowmanager/intern/wm_gesture_ops.c
+++ b/source/blender/windowmanager/intern/wm_gesture_ops.c
@@ -47,7 +47,6 @@
#include "wm.h"
#include "wm_event_types.h"
#include "wm_event_system.h"
-#include "wm_subwindow.h"
#include "ED_screen.h"
@@ -198,18 +197,15 @@ int WM_gesture_border_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
wmGesture *gesture = op->customdata;
rcti *rect = gesture->customdata;
- int sx, sy;
if (event->type == MOUSEMOVE) {
- wm_subwindow_origin_get(CTX_wm_window(C), gesture->swinid, &sx, &sy);
-
if (gesture->type == WM_GESTURE_CROSS_RECT && gesture->is_active == false) {
- rect->xmin = rect->xmax = event->x - sx;
- rect->ymin = rect->ymax = event->y - sy;
+ rect->xmin = rect->xmax = event->x - gesture->winrct.xmin;
+ rect->ymin = rect->ymax = event->y - gesture->winrct.ymin;
}
else {
- rect->xmax = event->x - sx;
- rect->ymax = event->y - sy;
+ rect->xmax = event->x - gesture->winrct.xmin;
+ rect->ymax = event->y - gesture->winrct.ymin;
}
gesture_border_apply_rect(op);
@@ -333,13 +329,11 @@ int WM_gesture_circle_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
wmGesture *gesture = op->customdata;
rcti *rect = gesture->customdata;
- int sx, sy;
if (event->type == MOUSEMOVE) {
- wm_subwindow_origin_get(CTX_wm_window(C), gesture->swinid, &sx, &sy);
- rect->xmin = event->x - sx;
- rect->ymin = event->y - sy;
+ rect->xmin = event->x - gesture->winrct.xmin;
+ rect->ymin = event->y - gesture->winrct.ymin;
wm_gesture_tag_redraw(C);
@@ -464,24 +458,22 @@ static void gesture_tweak_modal(bContext *C, const wmEvent *event)
wmWindow *window = CTX_wm_window(C);
wmGesture *gesture = window->tweak;
rcti *rect = gesture->customdata;
- int sx, sy, val;
+ int val;
switch (event->type) {
case MOUSEMOVE:
case INBETWEEN_MOUSEMOVE:
- wm_subwindow_origin_get(window, gesture->swinid, &sx, &sy);
-
- rect->xmax = event->x - sx;
- rect->ymax = event->y - sy;
+ rect->xmax = event->x - gesture->winrct.xmin;
+ rect->ymax = event->y - gesture->winrct.ymin;
if ((val = wm_gesture_evaluate(gesture))) {
wmEvent tevent;
wm_event_init_from_window(window, &tevent);
/* We want to get coord from start of drag, not from point where it becomes a tweak event, see T40549 */
- tevent.x = rect->xmin + sx;
- tevent.y = rect->ymin + sy;
+ tevent.x = rect->xmin + gesture->winrct.xmin;
+ tevent.y = rect->ymin + gesture->winrct.ymin;
if (gesture->event_type == LEFTMOUSE)
tevent.type = EVT_TWEAK_L;
else if (gesture->event_type == RIGHTMOUSE)
@@ -617,7 +609,6 @@ static void gesture_lasso_apply(bContext *C, wmOperator *op)
int WM_gesture_lasso_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
wmGesture *gesture = op->customdata;
- int sx, sy;
switch (event->type) {
case MOUSEMOVE:
@@ -625,8 +616,6 @@ int WM_gesture_lasso_modal(bContext *C, wmOperator *op, const wmEvent *event)
wm_gesture_tag_redraw(C);
- wm_subwindow_origin_get(CTX_wm_window(C), gesture->swinid, &sx, &sy);
-
if (gesture->points == gesture->points_alloc) {
gesture->points_alloc *= 2;
gesture->customdata = MEM_reallocN(gesture->customdata, sizeof(short[2]) * gesture->points_alloc);
@@ -637,15 +626,15 @@ int WM_gesture_lasso_modal(bContext *C, wmOperator *op, const wmEvent *event)
short *lasso = gesture->customdata;
lasso += (2 * gesture->points - 2);
- x = (event->x - sx - lasso[0]);
- y = (event->y - sy - lasso[1]);
+ x = (event->x - gesture->winrct.xmin - lasso[0]);
+ y = (event->y - gesture->winrct.ymin - lasso[1]);
/* make a simple distance check to get a smoother lasso
* add only when at least 2 pixels between this and previous location */
if ((x * x + y * y) > 4) {
lasso += 2;
- lasso[0] = event->x - sx;
- lasso[1] = event->y - sy;
+ lasso[0] = event->x - gesture->winrct.xmin;
+ lasso[1] = event->y - gesture->winrct.ymin;
gesture->points++;
}
}
@@ -813,18 +802,15 @@ int WM_gesture_straightline_modal(bContext *C, wmOperator *op, const wmEvent *ev
{
wmGesture *gesture = op->customdata;
rcti *rect = gesture->customdata;
- int sx, sy;
if (event->type == MOUSEMOVE) {
- wm_subwindow_origin_get(CTX_wm_window(C), gesture->swinid, &sx, &sy);
-
if (gesture->is_active == false) {
- rect->xmin = rect->xmax = event->x - sx;
- rect->ymin = rect->ymax = event->y - sy;
+ rect->xmin = rect->xmax = event->x - gesture->winrct.xmin;
+ rect->ymin = rect->ymax = event->y - gesture->winrct.ymin;
}
else {
- rect->xmax = event->x - sx;
- rect->ymax = event->y - sy;
+ rect->xmax = event->x - gesture->winrct.xmin;
+ rect->ymax = event->y - gesture->winrct.ymin;
gesture_straightline_apply(C, op);
}
diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c
index 088327fa611..6c374f3d8d4 100644
--- a/source/blender/windowmanager/intern/wm_init_exit.c
+++ b/source/blender/windowmanager/intern/wm_init_exit.c
@@ -61,7 +61,6 @@
#include "BKE_blender_undo.h"
#include "BKE_context.h"
#include "BKE_screen.h"
-#include "BKE_DerivedMesh.h"
#include "BKE_global.h"
#include "BKE_icons.h"
#include "BKE_library.h"
@@ -75,6 +74,7 @@
#include "BKE_addon.h"
#include "BKE_appdir.h"
#include "BKE_sequencer.h" /* free seq clipboard */
+#include "BKE_studiolight.h"
#include "BKE_material.h" /* clear_matcopybuf */
#include "BKE_tracking.h" /* free tracking clipboard */
#include "BKE_mask.h" /* free mask clipboard */
@@ -86,9 +86,6 @@
#include "BPY_extern.h"
#endif
-#ifdef WITH_GAMEENGINE
-# include "BL_System.h"
-#endif
#include "GHOST_Path-api.h"
#include "GHOST_C-api.h"
@@ -96,6 +93,7 @@
#include "WM_api.h"
#include "WM_types.h"
+#include "WM_message.h"
#include "wm_cursors.h"
#include "wm_event_system.h"
@@ -119,14 +117,17 @@
#include "BLF_api.h"
#include "BLT_lang.h"
-#include "GPU_buffers.h"
+#include "GPU_material.h"
#include "GPU_draw.h"
#include "GPU_init_exit.h"
-#include "BKE_depsgraph.h"
#include "BKE_sound.h"
#include "COM_compositor.h"
+#include "DEG_depsgraph.h"
+
+#include "DRW_engine.h"
+
#ifdef WITH_OPENSUBDIV
# include "BKE_subsurf.h"
#endif
@@ -135,6 +136,9 @@ CLG_LOGREF_DECLARE_GLOBAL(WM_LOG_OPERATORS, "wm.operator");
CLG_LOGREF_DECLARE_GLOBAL(WM_LOG_HANDLERS, "wm.handler");
CLG_LOGREF_DECLARE_GLOBAL(WM_LOG_EVENTS, "wm.event");
CLG_LOGREF_DECLARE_GLOBAL(WM_LOG_KEYMAPS, "wm.keymap");
+CLG_LOGREF_DECLARE_GLOBAL(WM_LOG_TOOLS, "wm.tool");
+CLG_LOGREF_DECLARE_GLOBAL(WM_LOG_MSGBUS_PUB, "wm.msgbus.pub");
+CLG_LOGREF_DECLARE_GLOBAL(WM_LOG_MSGBUS_SUB, "wm.msgbus.sub");
static void wm_init_reports(bContext *C)
{
@@ -153,6 +157,42 @@ static void wm_free_reports(bContext *C)
bool wm_start_with_console = false; /* used in creator.c */
+/**
+ * Since we cannot know in advance if we will require the draw manager
+ * context when starting blender in background mode (specially true with
+ * scripts) we deferre the ghost initialization the most as possible
+ * so that it does not break anything that can run in headless mode (as in
+ * without display server attached).
+ **/
+static bool opengl_is_init = false;
+
+void WM_init_opengl(Main *bmain)
+{
+ /* must be called only once */
+ BLI_assert(opengl_is_init == false);
+
+ if (G.background) {
+ /* Ghost is still not init elsewhere in background mode. */
+ wm_ghost_init(NULL);
+ }
+
+ /* Needs to be first to have an ogl context bound. */
+ DRW_opengl_context_create();
+
+ GPU_init();
+ GPU_set_mipmap(bmain, true);
+ GPU_set_linear_mipmap(true);
+ GPU_set_anisotropic(bmain, U.anisotropic_filter);
+ GPU_set_gpu_mipmapping(bmain, U.use_gpu_mipmap);
+
+ GPU_pass_cache_init();
+
+#ifdef WITH_OPENSUBDIV
+ BKE_subsurf_osd_init();
+#endif
+ opengl_is_init = true;
+}
+
/* only called once, for startup */
void WM_init(bContext *C, int argc, const char **argv)
{
@@ -161,6 +201,7 @@ void WM_init(bContext *C, int argc, const char **argv)
wm_ghost_init(C); /* note: it assigns C to ghost! */
wm_init_cursor_data();
}
+
GHOST_CreateSystemPaths();
BKE_addon_pref_type_init();
@@ -170,34 +211,38 @@ void WM_init(bContext *C, int argc, const char **argv)
WM_menutype_init();
WM_uilisttype_init();
+ wm_manipulatortype_init();
+ wm_manipulatorgrouptype_init();
ED_undosys_type_init();
BKE_library_callback_free_window_manager_set(wm_close_and_free); /* library.c */
BKE_library_callback_free_notifier_reference_set(WM_main_remove_notifier_reference); /* library.c */
+ BKE_region_callback_free_manipulatormap_set(wm_manipulatormap_remove); /* screen.c */
+ BKE_region_callback_refresh_tag_manipulatormap_set(WM_manipulatormap_tag_refresh);
BKE_library_callback_remap_editor_id_reference_set(WM_main_remap_editor_id_reference); /* library.c */
BKE_blender_callback_test_break_set(wm_window_testbreak); /* blender.c */
BKE_spacedata_callback_id_remap_set(ED_spacedata_id_remap); /* screen.c */
- DAG_editors_update_cb(ED_render_id_flush_update,
- ED_render_scene_update,
- ED_render_scene_update_pre); /* depsgraph.c */
+ DEG_editors_set_update_cb(ED_render_id_flush_update,
+ ED_render_scene_update);
ED_spacetypes_init(); /* editors/space_api/spacetype.c */
ED_file_init(); /* for fsmenu */
ED_node_init_butfuncs();
- BLF_init(); /* Please update source/gamengine/GamePlayer/GPG_ghost.cpp if you change this */
+ BLF_init();
BLT_lang_init();
/* reports cant be initialized before the wm,
* but keep before file reading, since that may report errors */
wm_init_reports(C);
+ WM_msgbus_types_init();
+
/* get the default database, plus a wm */
wm_homefile_read(C, NULL, G.factory_startup, false, true, NULL, NULL);
-
BLT_lang_set(NULL);
if (!G.background) {
@@ -206,19 +251,10 @@ void WM_init(bContext *C, int argc, const char **argv)
/* sets 3D mouse deadzone */
WM_ndof_deadzone_set(U.ndof_deadzone);
#endif
-
- GPU_init();
-
- GPU_set_mipmap(G_MAIN, !(U.gameflags & USER_DISABLE_MIPMAP));
- GPU_set_linear_mipmap(true);
- GPU_set_anisotropic(G_MAIN, U.anisotropic_filter);
- GPU_set_gpu_mipmapping(G_MAIN, U.use_gpu_mipmap);
-
-#ifdef WITH_OPENSUBDIV
- BKE_subsurf_osd_init();
-#endif
+ WM_init_opengl(G_MAIN);
UI_init();
+ BKE_studiolight_init();
}
else {
/* Note: Currently only inits icons, which we now want in background mode too
@@ -228,7 +264,6 @@ void WM_init(bContext *C, int argc, const char **argv)
BKE_icons_init(1);
}
-
ED_spacemacros_init();
/* note: there is a bug where python needs initializing before loading the
@@ -255,7 +290,7 @@ void WM_init(bContext *C, int argc, const char **argv)
clear_matcopybuf();
ED_render_clear_mtex_copybuf();
- // glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ // glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
wm_history_file_read();
@@ -316,96 +351,6 @@ void WM_init_splash(bContext *C)
}
}
-bool WM_init_game(bContext *C)
-{
- wmWindowManager *wm = CTX_wm_manager(C);
- wmWindow *win;
-
- ScrArea *sa;
- ARegion *ar = NULL;
-
- Scene *scene = CTX_data_scene(C);
-
- if (!scene) {
- /* XXX, this should not be needed. */
- Main *bmain = CTX_data_main(C);
- scene = bmain->scene.first;
- }
-
- win = wm->windows.first;
-
- /* first to get a valid window */
- if (win)
- CTX_wm_window_set(C, win);
-
- sa = BKE_screen_find_big_area(CTX_wm_screen(C), SPACE_VIEW3D, 0);
- ar = BKE_area_find_region_type(sa, RGN_TYPE_WINDOW);
-
- /* if we have a valid 3D view */
- if (sa && ar) {
- ARegion *arhide;
-
- CTX_wm_area_set(C, sa);
- CTX_wm_region_set(C, ar);
-
- /* disable quad view */
- if (ar->alignment == RGN_ALIGN_QSPLIT)
- WM_operator_name_call(C, "SCREEN_OT_region_quadview", WM_OP_EXEC_DEFAULT, NULL);
-
- /* toolbox, properties panel and header are hidden */
- for (arhide = sa->regionbase.first; arhide; arhide = arhide->next) {
- if (arhide->regiontype != RGN_TYPE_WINDOW) {
- if (!(arhide->flag & RGN_FLAG_HIDDEN)) {
- ED_region_toggle_hidden(C, arhide);
- }
- }
- }
-
- /* full screen the area */
- if (!sa->full) {
- ED_screen_state_toggle(C, win, sa, SCREENMAXIMIZED);
- }
-
- /* Fullscreen */
- if ((scene->gm.playerflag & GAME_PLAYER_FULLSCREEN)) {
- WM_operator_name_call(C, "WM_OT_window_fullscreen_toggle", WM_OP_EXEC_DEFAULT, NULL);
- wm_get_screensize(&ar->winrct.xmax, &ar->winrct.ymax);
- ar->winx = ar->winrct.xmax + 1;
- ar->winy = ar->winrct.ymax + 1;
- }
- else {
- GHOST_RectangleHandle rect = GHOST_GetClientBounds(win->ghostwin);
- ar->winrct.ymax = GHOST_GetHeightRectangle(rect);
- ar->winrct.xmax = GHOST_GetWidthRectangle(rect);
- ar->winx = ar->winrct.xmax + 1;
- ar->winy = ar->winrct.ymax + 1;
- GHOST_DisposeRectangle(rect);
- }
-
- WM_operator_name_call(C, "VIEW3D_OT_game_start", WM_OP_EXEC_DEFAULT, NULL);
-
- BKE_sound_exit();
-
- return true;
- }
- else {
- ReportTimerInfo *rti;
-
- BKE_report(&wm->reports, RPT_ERROR, "No valid 3D View found, game auto start is not possible");
-
- /* After adding the report to the global list, reset the report timer. */
- WM_event_remove_timer(wm, NULL, wm->reports.reporttimer);
-
- /* Records time since last report was added */
- wm->reports.reporttimer = WM_event_add_timer(wm, CTX_wm_window(C), TIMER, 0.02);
-
- rti = MEM_callocN(sizeof(ReportTimerInfo), "ReportTimerInfo");
- wm->reports.reporttimer->customdata = rti;
-
- return false;
- }
-}
-
/* free strings of open recent files */
static void free_openrecent(void)
{
@@ -483,7 +428,7 @@ void WM_exit_ext(bContext *C, const bool do_python)
/* save the undo state as quit.blend */
char filename[FILE_MAX];
bool has_edited;
- int fileflags = G.fileflags & ~(G_FILE_COMPRESS | G_FILE_AUTOPLAY | G_FILE_HISTORY);
+ int fileflags = G.fileflags & ~(G_FILE_COMPRESS | G_FILE_HISTORY);
BLI_make_file_string("/", filename, BKE_tempdir_base(), BLENDER_QUIT_FILE);
@@ -504,7 +449,7 @@ void WM_exit_ext(bContext *C, const bool do_python)
CTX_wm_window_set(C, win); /* needed by operator close callbacks */
WM_event_remove_handlers(C, &win->handlers);
WM_event_remove_handlers(C, &win->modalhandlers);
- ED_screen_exit(C, win, win->screen);
+ ED_screen_exit(C, win, WM_window_get_active_screen(win));
}
}
@@ -520,11 +465,6 @@ void WM_exit_ext(bContext *C, const bool do_python)
ED_undosys_type_free();
-// XXX
-// BIF_GlobalReebFree();
-// BIF_freeRetarget();
- BIF_freeTemplates(C);
-
free_openrecent();
BKE_mball_cubeTable_free();
@@ -547,6 +487,14 @@ void WM_exit_ext(bContext *C, const bool do_python)
COM_deinitialize();
#endif
+ if (opengl_is_init) {
+#ifdef WITH_OPENSUBDIV
+ BKE_subsurf_osd_cleanup();
+#endif
+
+ GPU_free_unused_buffers(G_MAIN);
+ }
+
BKE_blender_free(); /* blender.c, does entire library and spacetypes */
// free_matcopybuf();
ANIM_fcurves_copybuf_free();
@@ -557,8 +505,19 @@ void WM_exit_ext(bContext *C, const bool do_python)
ED_gpencil_strokes_copybuf_free();
BKE_node_clipboard_clear();
+ /* free manipulator-maps after freeing blender, so no deleted data get accessed during cleaning up of areas */
+ wm_manipulatormaptypes_free();
+ wm_manipulatorgrouptype_free();
+ wm_manipulatortype_free();
+
BLF_exit();
+ if (opengl_is_init) {
+ GPU_pass_cache_free();
+ DRW_opengl_context_destroy();
+ GPU_exit();
+ }
+
#ifdef WITH_INTERNATIONAL
BLF_free_unifont();
BLF_free_unifont_mono();
@@ -586,17 +545,6 @@ void WM_exit_ext(bContext *C, const bool do_python)
(void)do_python;
#endif
- if (!G.background) {
-#ifdef WITH_OPENSUBDIV
- BKE_subsurf_osd_cleanup();
-#endif
-
- GPU_global_buffer_pool_free();
- GPU_free_unused_buffers(G_MAIN);
-
- GPU_exit();
- }
-
ED_file_exit(); /* for fsmenu */
UI_exit();
@@ -607,9 +555,6 @@ void WM_exit_ext(bContext *C, const bool do_python)
wm_ghost_exit();
CTX_free(C);
-#ifdef WITH_GAMEENGINE
- SYS_DeleteSystem(SYS_GetSystem());
-#endif
GHOST_DisposeSystemPaths();
diff --git a/source/blender/windowmanager/intern/wm_keymap.c b/source/blender/windowmanager/intern/wm_keymap.c
index 762cef4a635..82363c4c21b 100644
--- a/source/blender/windowmanager/intern/wm_keymap.c
+++ b/source/blender/windowmanager/intern/wm_keymap.c
@@ -38,6 +38,7 @@
#include "DNA_space_types.h"
#include "DNA_userdef_types.h"
#include "DNA_windowmanager_types.h"
+#include "DNA_workspace_types.h"
#include "MEM_guardedalloc.h"
#include "CLG_log.h"
@@ -51,6 +52,7 @@
#include "BKE_global.h"
#include "BKE_main.h"
#include "BKE_screen.h"
+#include "BKE_workspace.h"
#include "BLT_translation.h"
@@ -164,7 +166,8 @@ static void wm_keyconfig_properties_update_ot(ListBase *km_lb)
static bool wm_keymap_item_equals_result(wmKeyMapItem *a, wmKeyMapItem *b)
{
return (STREQ(a->idname, b->idname) &&
- RNA_struct_equals(a->ptr, b->ptr, RNA_EQ_UNSET_MATCH_NONE) &&
+ /* We do not really care about which Main we pass here, tbh. */
+ RNA_struct_equals(G_MAIN, a->ptr, b->ptr, RNA_EQ_UNSET_MATCH_NONE) &&
(a->flag & KMI_INACTIVE) == (b->flag & KMI_INACTIVE) &&
a->propvalue == b->propvalue);
}
@@ -343,6 +346,12 @@ static wmKeyMap *wm_keymap_new(const char *idname, int spaceid, int regionid)
km->spaceid = spaceid;
km->regionid = regionid;
+ {
+ const char *owner_id = RNA_struct_state_owner_get();
+ if (owner_id) {
+ BLI_strncpy(km->owner_id, owner_id, sizeof(km->owner_id));
+ }
+ }
return km;
}
@@ -403,6 +412,14 @@ bool WM_keymap_remove(wmKeyConfig *keyconf, wmKeyMap *keymap)
bool WM_keymap_poll(bContext *C, wmKeyMap *keymap)
{
+ /* If we're tagged, only use compatible. */
+ if (keymap->owner_id[0] != '\0') {
+ const WorkSpace *workspace = CTX_wm_workspace(C);
+ if (BKE_workspace_owner_id_check(workspace, keymap->owner_id) == false) {
+ return false;
+ }
+ }
+
if (keymap->poll != NULL) {
return keymap->poll(C);
}
@@ -492,6 +509,28 @@ wmKeyMapItem *WM_keymap_add_menu_pie(wmKeyMap *keymap, const char *idname, int t
return kmi;
}
+wmKeyMapItem *WM_keymap_add_panel(
+ wmKeyMap *keymap,
+ short space_type, short region_type, const char *idname,
+ int type, int val, int modifier, int keymodifier)
+{
+ wmKeyMapItem *kmi = WM_keymap_add_item(keymap, "WM_OT_call_panel", type, val, modifier, keymodifier);
+ RNA_enum_set(kmi->ptr, "space_type", space_type);
+ RNA_enum_set(kmi->ptr, "region_type", region_type);
+ RNA_string_set(kmi->ptr, "name", idname);
+ /* TODO: we might want to disable this. */
+ RNA_boolean_set(kmi->ptr, "keep_open", false);
+ return kmi;
+}
+
+/* tool wrapper for WM_keymap_add_item */
+wmKeyMapItem *WM_keymap_add_tool(wmKeyMap *keymap, const char *idname, int type, int val, int modifier, int keymodifier)
+{
+ wmKeyMapItem *kmi = WM_keymap_add_item(keymap, "WM_OT_tool_set_by_name", type, val, modifier, keymodifier);
+ RNA_string_set(kmi->ptr, "name", idname);
+ return kmi;
+}
+
bool WM_keymap_remove_item(wmKeyMap *keymap, wmKeyMapItem *kmi)
{
if (BLI_findindex(&keymap->items, kmi) != -1) {
@@ -968,11 +1007,7 @@ int WM_keymap_item_raw_to_string(
alt == KM_ANY &&
oskey == KM_ANY)
{
- /* make it implicit in case of compact result expected. */
- if (!compact) {
- ADD_SEP;
- p += BLI_strcpy_rlen(p, IFACE_("Any"));
- }
+ /* Don't show anything for any mapping. */
}
else {
if (shift) {
@@ -1807,10 +1842,6 @@ wmKeyMap *WM_keymap_guess_opname(const bContext *C, const char *opname)
break;
}
}
- /* Timeline */
- else if (STRPREFIX(opname, "TIME_OT")) {
- km = WM_keymap_find_all(C, "Timeline", sl->spacetype, 0);
- }
/* Image Editor */
else if (STRPREFIX(opname, "IMAGE_OT")) {
km = WM_keymap_find_all(C, "Image", sl->spacetype, 0);
diff --git a/source/blender/windowmanager/intern/wm_operator_props.c b/source/blender/windowmanager/intern/wm_operator_props.c
index cfad1db132c..d4fb7279abc 100644
--- a/source/blender/windowmanager/intern/wm_operator_props.c
+++ b/source/blender/windowmanager/intern/wm_operator_props.c
@@ -130,7 +130,9 @@ void WM_operator_properties_filesel(
static void wm_operator_properties_select_action_ex(wmOperatorType *ot, int default_action,
const EnumPropertyItem *select_actions)
{
- RNA_def_enum(ot->srna, "action", select_actions, default_action, "Action", "Selection action to execute");
+ PropertyRNA *prop;
+ prop = RNA_def_enum(ot->srna, "action", select_actions, default_action, "Action", "Selection action to execute");
+ RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE);
}
void WM_operator_properties_select_action(wmOperatorType *ot, int default_action)
diff --git a/source/blender/windowmanager/intern/wm_operator_type.c b/source/blender/windowmanager/intern/wm_operator_type.c
index 62b378e0866..89421ac0ab0 100644
--- a/source/blender/windowmanager/intern/wm_operator_type.c
+++ b/source/blender/windowmanager/intern/wm_operator_type.c
@@ -46,6 +46,7 @@
#include "RNA_access.h"
#include "RNA_define.h"
+#include "RNA_enum_types.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -62,6 +63,8 @@ static void wm_operatortype_free_macro(wmOperatorType *ot);
* \{ */
static GHash *global_ops_hash = NULL;
+/** Counter for operator-properties that should not be tagged with #OP_PROP_TAG_ADVANCED. */
+static int ot_prop_basic_count = -1;
wmOperatorType *WM_operatortype_find(const char *idname, bool quiet)
{
@@ -96,22 +99,32 @@ void WM_operatortype_iter(GHashIterator *ghi)
BLI_ghashIterator_init(ghi, global_ops_hash);
}
-/* all ops in 1 list (for time being... needs evaluation later) */
-void WM_operatortype_append(void (*opfunc)(wmOperatorType *))
+/** \name Operator Type Append
+ * \{ */
+
+static wmOperatorType *wm_operatortype_append__begin(void)
{
- wmOperatorType *ot;
+ wmOperatorType *ot = MEM_callocN(sizeof(wmOperatorType), "operatortype");
+
+ BLI_assert(ot_prop_basic_count == -1);
- ot = MEM_callocN(sizeof(wmOperatorType), "operatortype");
ot->srna = RNA_def_struct_ptr(&BLENDER_RNA, "", &RNA_OperatorProperties);
+ RNA_def_struct_property_tags(ot->srna, rna_enum_operator_property_tags);
/* Set the default i18n context now, so that opfunc can redefine it if needed! */
RNA_def_struct_translation_context(ot->srna, BLT_I18NCONTEXT_OPERATOR_DEFAULT);
ot->translation_context = BLT_I18NCONTEXT_OPERATOR_DEFAULT;
- opfunc(ot);
+ return ot;
+}
+static void wm_operatortype_append__end(wmOperatorType *ot)
+{
if (ot->name == NULL) {
CLOG_ERROR(WM_LOG_OPERATORS, "Operator '%s' has no name property", ot->idname);
}
+ /* Allow calling _begin without _end in operatortype creation. */
+ WM_operatortype_props_advanced_end(ot);
+
/* XXX All ops should have a description but for now allow them not to. */
RNA_def_struct_ui_text(ot->srna, ot->name, ot->description ? ot->description : UNDOCUMENTED_OPERATOR_TIP);
RNA_def_struct_identifier(&BLENDER_RNA, ot->srna, ot->idname);
@@ -119,22 +132,23 @@ void WM_operatortype_append(void (*opfunc)(wmOperatorType *))
BLI_ghash_insert(global_ops_hash, (void *)ot->idname, ot);
}
-void WM_operatortype_append_ptr(void (*opfunc)(wmOperatorType *, void *), void *userdata)
+/* all ops in 1 list (for time being... needs evaluation later) */
+void WM_operatortype_append(void (*opfunc)(wmOperatorType *))
{
- wmOperatorType *ot;
+ wmOperatorType *ot = wm_operatortype_append__begin();
+ opfunc(ot);
+ wm_operatortype_append__end(ot);
+}
- ot = MEM_callocN(sizeof(wmOperatorType), "operatortype");
- ot->srna = RNA_def_struct_ptr(&BLENDER_RNA, "", &RNA_OperatorProperties);
- /* Set the default i18n context now, so that opfunc can redefine it if needed! */
- RNA_def_struct_translation_context(ot->srna, BLT_I18NCONTEXT_OPERATOR_DEFAULT);
- ot->translation_context = BLT_I18NCONTEXT_OPERATOR_DEFAULT;
+void WM_operatortype_append_ptr(void (*opfunc)(wmOperatorType *, void *), void *userdata)
+{
+ wmOperatorType *ot = wm_operatortype_append__begin();
opfunc(ot, userdata);
- RNA_def_struct_ui_text(ot->srna, ot->name, ot->description ? ot->description : UNDOCUMENTED_OPERATOR_TIP);
- RNA_def_struct_identifier(&BLENDER_RNA, ot->srna, ot->idname);
-
- BLI_ghash_insert(global_ops_hash, (void *)ot->idname, ot);
+ wm_operatortype_append__end(ot);
}
+/** \} */
+
/* called on initialize WM_exit() */
void WM_operatortype_remove_ptr(wmOperatorType *ot)
@@ -200,6 +214,55 @@ void wm_operatortype_free(void)
}
/**
+ * Tag all operator-properties of \a ot defined after calling this, until
+ * the next #WM_operatortype_props_advanced_end call (if available), with
+ * #OP_PROP_TAG_ADVANCED. Previously defined ones properties not touched.
+ *
+ * Calling this multiple times without a call to #WM_operatortype_props_advanced_end,
+ * all calls after the first one are ignored. Meaning all propereties defined after the
+ * first call are tagged as advanced.
+ *
+ * This doesn't do the actual tagging, #WM_operatortype_props_advanced_end does which is
+ * called for all operators during registration (see #wm_operatortype_append__end).
+ */
+void WM_operatortype_props_advanced_begin(wmOperatorType *ot)
+{
+ if (ot_prop_basic_count == -1) { /* Don't do anything if _begin was called before, but not _end */
+ ot_prop_basic_count = RNA_struct_count_properties(ot->srna);
+ }
+}
+
+/**
+ * Tags all operator-properties of \ot defined since the first #WM_operatortype_props_advanced_begin
+ * call, or the last #WM_operatortype_props_advanced_end call, with #OP_PROP_TAG_ADVANCED.
+ * Note that this is called for all operators during registration (see #wm_operatortype_append__end).
+ * So it does not need to be explicitly called in operator-type definition.
+ */
+void WM_operatortype_props_advanced_end(wmOperatorType *ot)
+{
+ PointerRNA struct_ptr;
+ int counter = 0;
+
+ if (ot_prop_basic_count == -1) {
+ /* WM_operatortype_props_advanced_begin was not called. Don't do anything. */
+ return;
+ }
+
+ RNA_pointer_create(NULL, ot->srna, NULL, &struct_ptr);
+
+ RNA_STRUCT_BEGIN (&struct_ptr, prop)
+ {
+ counter++;
+ if (counter > ot_prop_basic_count) {
+ WM_operatortype_prop_tag(prop, OP_PROP_TAG_ADVANCED);
+ }
+ }
+ RNA_STRUCT_END;
+
+ ot_prop_basic_count = -1;
+}
+
+/**
* Remove memory of all previously executed tools.
*/
void WM_operatortype_last_properties_clear_all(void)
diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c
index ffa6b0fc371..5cb95f2b3c5 100644
--- a/source/blender/windowmanager/intern/wm_operators.c
+++ b/source/blender/windowmanager/intern/wm_operators.c
@@ -54,6 +54,7 @@
#include "DNA_scene_types.h"
#include "DNA_userdef_types.h"
#include "DNA_windowmanager_types.h"
+#include "DNA_workspace_types.h"
#include "BLT_translation.h"
@@ -72,7 +73,6 @@
#include "BKE_blender_version.h"
#include "BKE_brush.h"
#include "BKE_context.h"
-#include "BKE_depsgraph.h"
#include "BKE_icons.h"
#include "BKE_idprop.h"
#include "BKE_image.h"
@@ -88,9 +88,12 @@
#include "BKE_idcode.h"
-#include "BIF_glutil.h" /* for paint cursor */
#include "BLF_api.h"
+#include "GPU_immediate.h"
+#include "GPU_immediate_util.h"
+#include "GPU_matrix.h"
+
#include "IMB_imbuf_types.h"
#include "IMB_imbuf.h"
@@ -99,8 +102,6 @@
#include "ED_undo.h"
#include "ED_view3d.h"
-#include "GPU_basic_shader.h"
-
#include "RNA_access.h"
#include "RNA_define.h"
#include "RNA_enum_types.h"
@@ -336,7 +337,7 @@ bool WM_operator_pystring_abbreviate(char *str, int str_len_max)
/* return NULL if no match is found */
#if 0
-static const char *wm_context_member_from_ptr(bContext *C, PointerRNA *ptr)
+static const char *wm_context_member_from_ptr(bContext *C, const PointerRNA *ptr)
{
/* loop over all context items and do 2 checks
*
@@ -391,7 +392,7 @@ static const char *wm_context_member_from_ptr(bContext *C, PointerRNA *ptr)
/* use hard coded checks for now */
-static const char *wm_context_member_from_ptr(bContext *C, PointerRNA *ptr)
+static const char *wm_context_member_from_ptr(bContext *C, const PointerRNA *ptr)
{
const char *member_id = NULL;
@@ -477,6 +478,8 @@ static const char *wm_context_member_from_ptr(bContext *C, PointerRNA *ptr)
SpaceLink *space_data = CTX_wm_space_data(C);
CTX_TEST_PTR_DATA_TYPE(C, "space_data", RNA_Space, ptr, space_data);
+ CTX_TEST_PTR_DATA_TYPE(C, "space_data", RNA_View3DOverlay, ptr, space_data);
+ CTX_TEST_PTR_DATA_TYPE(C, "space_data", RNA_View3DShading, ptr, space_data);
CTX_TEST_PTR_DATA_TYPE(C, "area", RNA_Area, ptr, CTX_wm_area(C));
CTX_TEST_PTR_DATA_TYPE(C, "region", RNA_Region, ptr, CTX_wm_region(C));
@@ -514,6 +517,11 @@ static char *wm_prop_pystring_from_context(bContext *C, PointerRNA *ptr, Propert
return ret;
}
+const char *WM_context_member_from_ptr(bContext *C, const PointerRNA *ptr)
+{
+ return wm_context_member_from_ptr(C, ptr);
+}
+
char *WM_prop_pystring_assign(bContext *C, PointerRNA *ptr, PropertyRNA *prop, int index)
{
char *lhs, *rhs, *ret;
@@ -755,46 +763,70 @@ int WM_menu_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
return WM_menu_invoke_ex(C, op, WM_OP_INVOKE_REGION_WIN);
}
+struct EnumSearchMenu {
+ wmOperator *op; /* the operator that will be executed when selecting an item */
+
+ bool use_previews;
+ short prv_cols, prv_rows;
+};
/* generic enum search invoke popup */
-static uiBlock *wm_enum_search_menu(bContext *C, ARegion *ar, void *arg_op)
+static uiBlock *wm_enum_search_menu(bContext *C, ARegion *ar, void *arg)
{
- static char search[256] = "";
- wmEvent event;
+ struct EnumSearchMenu *search_menu = arg;
wmWindow *win = CTX_wm_window(C);
+ wmOperator *op = search_menu->op;
+ /* template_ID uses 4 * widget_unit for width, we use a bit more, some items may have a suffix to show */
+ const int width = search_menu->use_previews ? 5 * U.widget_unit * search_menu->prv_cols : UI_searchbox_size_x();
+ const int height = search_menu->use_previews ? 5 * U.widget_unit * search_menu->prv_rows : UI_searchbox_size_y();
+ static char search[256] = "";
uiBlock *block;
uiBut *but;
- wmOperator *op = (wmOperator *)arg_op;
block = UI_block_begin(C, ar, "_popup", UI_EMBOSS);
UI_block_flag_enable(block, UI_BLOCK_LOOP | UI_BLOCK_MOVEMOUSE_QUIT | UI_BLOCK_SEARCH_MENU);
search[0] = '\0';
+ BLI_assert(search_menu->use_previews || (search_menu->prv_cols == 0 && search_menu->prv_rows == 0));
#if 0 /* ok, this isn't so easy... */
uiDefBut(block, UI_BTYPE_LABEL, 0, RNA_struct_ui_name(op->type->srna), 10, 10, UI_searchbox_size_x(), UI_UNIT_Y, NULL, 0.0, 0.0, 0, 0, "");
#endif
but = uiDefSearchButO_ptr(block, op->type, op->ptr->data, search, 0, ICON_VIEWZOOM, sizeof(search),
- 10, 10, UI_searchbox_size_x(), UI_UNIT_Y, 0, 0, "");
+ 10, 10, width, UI_UNIT_Y, search_menu->prv_rows, search_menu->prv_cols, "");
/* fake button, it holds space for search items */
- uiDefBut(block, UI_BTYPE_LABEL, 0, "", 10, 10 - UI_searchbox_size_y(), UI_searchbox_size_x(), UI_searchbox_size_y(), NULL, 0, 0, 0, 0, NULL);
+ uiDefBut(block, UI_BTYPE_LABEL, 0, "", 10, 10 - UI_searchbox_size_y(), width, height, NULL, 0, 0, 0, 0, NULL);
UI_block_bounds_set_popup(block, 6, 0, -UI_UNIT_Y); /* move it downwards, mouse over button */
-
- wm_event_init_from_window(win, &event);
- event.type = EVT_BUT_OPEN;
- event.val = KM_PRESS;
- event.customdata = but;
- event.customdatafree = false;
- wm_event_add(win, &event);
+ UI_but_focus_on_enter_event(win, but);
return block;
}
+/**
+ * Similar to #WM_enum_search_invoke, but draws previews. Also, this can't
+ * be used as invoke callback directly since it needs additional info.
+ */
+int WM_enum_search_invoke_previews(
+ bContext *C, wmOperator *op, short prv_cols, short prv_rows)
+{
+ static struct EnumSearchMenu search_menu;
+
+ search_menu.op = op;
+ search_menu.use_previews = true;
+ search_menu.prv_cols = prv_cols;
+ search_menu.prv_rows = prv_rows;
+
+ UI_popup_block_invoke(C, wm_enum_search_menu, &search_menu);
+
+ return OPERATOR_INTERFACE;
+}
int WM_enum_search_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
{
- UI_popup_block_invoke(C, wm_enum_search_menu, op);
+ static struct EnumSearchMenu search_menu;
+ search_menu.op = op;
+ UI_popup_block_invoke(C, wm_enum_search_menu, &search_menu);
return OPERATOR_INTERFACE;
}
@@ -887,6 +919,21 @@ wmOperator *WM_operator_last_redo(const bContext *C)
return op;
}
+IDProperty *WM_operator_last_properties_ensure_idprops(wmOperatorType *ot)
+{
+ if (ot->last_properties == NULL) {
+ IDPropertyTemplate val = {0};
+ ot->last_properties = IDP_New(IDP_GROUP, &val, "wmOperatorProperties");
+ }
+ return ot->last_properties;
+}
+
+void WM_operator_last_properties_ensure(wmOperatorType *ot, PointerRNA *ptr)
+{
+ IDProperty *props = WM_operator_last_properties_ensure_idprops(ot);
+ RNA_pointer_create(NULL, ot->srna, props, ptr);
+}
+
/**
* Use for drag & drop a path or name with operators invoke() function.
*/
@@ -996,13 +1043,15 @@ static uiBlock *wm_block_create_redo(bContext *C, ARegion *ar, void *arg_op)
if (op->type->flag & OPTYPE_MACRO) {
for (op = op->macro.first; op; op = op->next) {
- uiTemplateOperatorPropertyButs(C, layout, op, NULL, 'H', UI_TEMPLATE_OP_PROPS_SHOW_TITLE);
+ uiTemplateOperatorPropertyButs(C, layout, op, NULL, UI_BUT_LABEL_ALIGN_SPLIT_COLUMN,
+ UI_TEMPLATE_OP_PROPS_SHOW_TITLE);
if (op->next)
uiItemS(layout);
}
}
else {
- uiTemplateOperatorPropertyButs(C, layout, op, NULL, 'H', UI_TEMPLATE_OP_PROPS_SHOW_TITLE);
+ uiTemplateOperatorPropertyButs(C, layout, op, NULL, UI_BUT_LABEL_ALIGN_SPLIT_COLUMN,
+ UI_TEMPLATE_OP_PROPS_SHOW_TITLE);
}
UI_block_bounds_set_popup(block, 4, 0, 0);
@@ -1071,7 +1120,8 @@ static uiBlock *wm_block_dialog_create(bContext *C, ARegion *ar, void *userData)
layout = UI_block_layout(block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 0, 0, data->width, data->height, 0, style);
- uiTemplateOperatorPropertyButs(C, layout, op, NULL, 'H', UI_TEMPLATE_OP_PROPS_SHOW_TITLE);
+ uiTemplateOperatorPropertyButs(C, layout, op, NULL, UI_BUT_LABEL_ALIGN_SPLIT_COLUMN,
+ UI_TEMPLATE_OP_PROPS_SHOW_TITLE);
/* clear so the OK button is left alone */
UI_block_func_set(block, NULL, NULL, NULL);
@@ -1110,7 +1160,7 @@ static uiBlock *wm_operator_ui_create(bContext *C, ARegion *ar, void *userData)
layout = UI_block_layout(block, UI_LAYOUT_VERTICAL, UI_LAYOUT_PANEL, 0, 0, data->width, data->height, 0, style);
/* since ui is defined the auto-layout args are not used */
- uiTemplateOperatorPropertyButs(C, layout, op, NULL, 'V', 0);
+ uiTemplateOperatorPropertyButs(C, layout, op, NULL, UI_BUT_LABEL_ALIGN_COLUMN, 0);
UI_block_func_set(block, NULL, NULL, NULL);
@@ -1411,7 +1461,7 @@ static uiBlock *wm_block_create_splash(bContext *C, ARegion *ar, void *UNUSED(ar
ibuf_template = IMB_loadiffname(splash_filepath, IB_rect, NULL);
if (ibuf_template) {
const int x_expect = ibuf->x;
- const int y_expect = 230 * (int)U.pixelsize;
+ const int y_expect = 282 * (int)U.pixelsize;
/* don't cover the header text */
if (ibuf_template->x == x_expect && ibuf_template->y == y_expect) {
memcpy(ibuf->rect, ibuf_template->rect, ibuf_template->x * ibuf_template->y * sizeof(char[4]));
@@ -1441,7 +1491,13 @@ static uiBlock *wm_block_create_splash(bContext *C, ARegion *ar, void *UNUSED(ar
/* label for 'a' bugfix releases, or 'Release Candidate 1'...
* avoids recreating splash for version updates */
- if (STREQ(STRINGIFY(BLENDER_VERSION_CYCLE), "rc")) {
+ if (STREQ(STRINGIFY(BLENDER_VERSION_CYCLE), "alpha")) {
+ version_suffix = "Alpha";
+ }
+ else if (STREQ(STRINGIFY(BLENDER_VERSION_CYCLE), "beta")) {
+ version_suffix = "Beta";
+ }
+ else if (STREQ(STRINGIFY(BLENDER_VERSION_CYCLE), "rc")) {
version_suffix = "Release Candidate";
}
else if (STREQ(STRINGIFY(BLENDER_VERSION_CYCLE), "release")) {
@@ -1450,8 +1506,8 @@ static uiBlock *wm_block_create_splash(bContext *C, ARegion *ar, void *UNUSED(ar
if (version_suffix != NULL && version_suffix[0]) {
/* placed after the version number in the image,
* placing y is tricky to match baseline */
- int x = 260 * U.pixelsize - (2 * UI_DPI_FAC);
- int y = 242 * U.pixelsize + (4 * UI_DPI_FAC);
+ int x = 236 * U.pixelsize - (2 * UI_DPI_FAC);
+ int y = 231 * U.pixelsize + (4 * UI_DPI_FAC);
int w = 240 * U.pixelsize;
/* hack to have text draw 'text_sel' */
@@ -1464,17 +1520,32 @@ static uiBlock *wm_block_create_splash(bContext *C, ARegion *ar, void *UNUSED(ar
#ifdef WITH_BUILDINFO
if (build_commit_timestamp != 0) {
- uiDefBut(block, UI_BTYPE_LABEL, 0, date_buf, U.pixelsize * 494 - date_width, U.pixelsize * 270, date_width, UI_UNIT_Y, NULL, 0, 0, 0, 0, NULL);
+ but = uiDefBut(
+ block, UI_BTYPE_LABEL, 0, date_buf,
+ U.pixelsize * 502 - date_width, U.pixelsize * 267,
+ date_width, UI_UNIT_Y, NULL, 0, 0, 0, 0, NULL);
+ /* XXX, set internal flag - UI_SELECT */
+ UI_but_flag_enable(but, 1);
label_delta = 12;
}
- uiDefBut(block, UI_BTYPE_LABEL, 0, hash_buf, U.pixelsize * 494 - hash_width, U.pixelsize * (270 - label_delta), hash_width, UI_UNIT_Y, NULL, 0, 0, 0, 0, NULL);
+ but = uiDefBut(
+ block, UI_BTYPE_LABEL, 0, hash_buf,
+ U.pixelsize * 502 - hash_width, U.pixelsize * (267 - label_delta),
+ hash_width, UI_UNIT_Y, NULL, 0, 0, 0, 0, NULL);
+ /* XXX, set internal flag - UI_SELECT */
+ UI_but_flag_enable(but, 1);
if (!STREQ(build_branch, "master")) {
char branch_buf[128] = "\0";
int branch_width;
BLI_snprintf(branch_buf, sizeof(branch_buf), "Branch: %s", build_branch);
branch_width = (int)BLF_width(style->widgetlabel.uifont_id, branch_buf, sizeof(branch_buf)) + U.widget_unit;
- uiDefBut(block, UI_BTYPE_LABEL, 0, branch_buf, U.pixelsize * 494 - branch_width, U.pixelsize * (258 - label_delta), branch_width, UI_UNIT_Y, NULL, 0, 0, 0, 0, NULL);
+ but = uiDefBut(
+ block, UI_BTYPE_LABEL, 0, branch_buf,
+ U.pixelsize * 502 - branch_width, U.pixelsize * (255 - label_delta),
+ branch_width, UI_UNIT_Y, NULL, 0, 0, 0, 0, NULL);
+ /* XXX, set internal flag - UI_SELECT */
+ UI_but_flag_enable(but, 1);
}
#endif /* WITH_BUILDINFO */
@@ -1494,10 +1565,8 @@ static uiBlock *wm_block_create_splash(bContext *C, ARegion *ar, void *UNUSED(ar
split = uiLayoutSplit(layout, 0.0f, false);
col = uiLayoutColumn(split, false);
uiItemL(col, IFACE_("Links"), ICON_NONE);
-#if 0
- uiItemStringO(col, IFACE_("Support an Open Animation Movie"), ICON_URL, "WM_OT_url_open", "url",
- "https://cloud.blender.org/join");
-#endif
+ uiItemStringO(col, IFACE_("Join the Development Fund"), ICON_URL, "WM_OT_url_open", "url",
+ "https://www.blender.org/foundation/development-fund/");
uiItemStringO(col, IFACE_("Donations"), ICON_URL, "WM_OT_url_open", "url",
"http://www.blender.org/foundation/donation-payment/");
uiItemStringO(col, IFACE_("Credits"), ICON_URL, "WM_OT_url_open", "url",
@@ -1705,6 +1774,40 @@ static void WM_OT_call_menu_pie(wmOperatorType *ot)
RNA_def_string(ot->srna, "name", NULL, BKE_ST_MAXNAME, "Name", "Name of the pie menu");
}
+static int wm_call_panel_exec(bContext *C, wmOperator *op)
+{
+ char idname[BKE_ST_MAXNAME];
+ RNA_string_get(op->ptr, "name", idname);
+ const int space_type = RNA_enum_get(op->ptr, "space_type");
+ const int region_type = RNA_enum_get(op->ptr, "region_type");
+ const bool keep_open = RNA_boolean_get(op->ptr, "keep_open");
+
+ return UI_popover_panel_invoke(C, space_type, region_type, idname, keep_open, op->reports);
+}
+
+static void WM_OT_call_panel(wmOperatorType *ot)
+{
+ ot->name = "Call Panel";
+ ot->idname = "WM_OT_call_panel";
+ ot->description = "Call (draw) a pre-defined panel";
+
+ ot->exec = wm_call_panel_exec;
+ ot->poll = WM_operator_winactive;
+
+ ot->flag = OPTYPE_INTERNAL;
+
+ PropertyRNA *prop;
+
+ prop = RNA_def_string(ot->srna, "name", NULL, BKE_ST_MAXNAME, "Name", "Name of the menu");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ prop = RNA_def_enum(ot->srna, "space_type", rna_enum_space_type_items, SPACE_EMPTY, "Space Type", "");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ prop = RNA_def_enum(ot->srna, "region_type", rna_enum_region_type_items, RGN_TYPE_WINDOW, "Region Type", "");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+ prop = RNA_def_boolean(ot->srna, "keep_open", true, "Keep Open", "");
+ RNA_def_property_flag(prop, PROP_SKIP_SAVE);
+}
+
/* ************ window / screen operator definitions ************** */
/* this poll functions is needed in place of WM_operator_winactive
@@ -1712,8 +1815,11 @@ static void WM_OT_call_menu_pie(wmOperatorType *ot)
static bool wm_operator_winactive_normal(bContext *C)
{
wmWindow *win = CTX_wm_window(C);
+ bScreen *screen;
- if (win == NULL || win->screen == NULL || win->screen->state != SCREENNORMAL)
+ if (win == NULL)
+ return 0;
+ if (!((screen = WM_window_get_active_screen(win)) && (screen->state == SCREENNORMAL)))
return 0;
return 1;
@@ -1724,19 +1830,29 @@ static void WM_OT_window_close(wmOperatorType *ot)
{
ot->name = "Close Window";
ot->idname = "WM_OT_window_close";
- ot->description = "Close the current Blender window";
+ ot->description = "Close the current window";
ot->exec = wm_window_close_exec;
ot->poll = WM_operator_winactive;
}
-static void WM_OT_window_duplicate(wmOperatorType *ot)
+static void WM_OT_window_new(wmOperatorType *ot)
{
- ot->name = "Duplicate Window";
- ot->idname = "WM_OT_window_duplicate";
- ot->description = "Duplicate the current Blender window";
+ ot->name = "New Window";
+ ot->idname = "WM_OT_window_new";
+ ot->description = "Create a new window";
- ot->exec = wm_window_duplicate_exec;
+ ot->exec = wm_window_new_exec;
+ ot->poll = wm_operator_winactive_normal;
+}
+
+static void WM_OT_window_new_main(wmOperatorType *ot)
+{
+ ot->name = "New Main Window";
+ ot->idname = "WM_OT_window_new_main";
+ ot->description = "Create a new main window with its own workspace and scene selection";
+
+ ot->exec = wm_window_new_main_exec;
ot->poll = wm_operator_winactive_normal;
}
@@ -1868,38 +1984,37 @@ static void radial_control_update_header(wmOperator *op, bContext *C)
ScrArea *sa = CTX_wm_area(C);
Scene *scene = CTX_data_scene(C);
- if (sa) {
- if (hasNumInput(&rc->num_input)) {
- char num_str[NUM_STR_REP_LEN];
- outputNumInput(&rc->num_input, num_str, &scene->unit);
- BLI_snprintf(msg, sizeof(msg), "%s: %s", RNA_property_ui_name(rc->prop), num_str);
- }
- else {
- const char *ui_name = RNA_property_ui_name(rc->prop);
- switch (rc->subtype) {
- case PROP_NONE:
- case PROP_DISTANCE:
- BLI_snprintf(msg, sizeof(msg), "%s: %0.4f", ui_name, rc->current_value);
- break;
- case PROP_PIXEL:
- BLI_snprintf(msg, sizeof(msg), "%s: %d", ui_name, (int)rc->current_value); /* XXX: round to nearest? */
- break;
- case PROP_PERCENTAGE:
- BLI_snprintf(msg, sizeof(msg), "%s: %3.1f%%", ui_name, rc->current_value);
- break;
- case PROP_FACTOR:
- BLI_snprintf(msg, sizeof(msg), "%s: %1.3f", ui_name, rc->current_value);
- break;
- case PROP_ANGLE:
- BLI_snprintf(msg, sizeof(msg), "%s: %3.2f", ui_name, RAD2DEGF(rc->current_value));
- break;
- default:
- BLI_snprintf(msg, sizeof(msg), "%s", ui_name); /* XXX: No value? */
- break;
- }
+ if (hasNumInput(&rc->num_input)) {
+ char num_str[NUM_STR_REP_LEN];
+ outputNumInput(&rc->num_input, num_str, &scene->unit);
+ BLI_snprintf(msg, sizeof(msg), "%s: %s", RNA_property_ui_name(rc->prop), num_str);
+ }
+ else {
+ const char *ui_name = RNA_property_ui_name(rc->prop);
+ switch (rc->subtype) {
+ case PROP_NONE:
+ case PROP_DISTANCE:
+ BLI_snprintf(msg, sizeof(msg), "%s: %0.4f", ui_name, rc->current_value);
+ break;
+ case PROP_PIXEL:
+ BLI_snprintf(msg, sizeof(msg), "%s: %d", ui_name, (int)rc->current_value); /* XXX: round to nearest? */
+ break;
+ case PROP_PERCENTAGE:
+ BLI_snprintf(msg, sizeof(msg), "%s: %3.1f%%", ui_name, rc->current_value);
+ break;
+ case PROP_FACTOR:
+ BLI_snprintf(msg, sizeof(msg), "%s: %1.3f", ui_name, rc->current_value);
+ break;
+ case PROP_ANGLE:
+ BLI_snprintf(msg, sizeof(msg), "%s: %3.2f", ui_name, RAD2DEGF(rc->current_value));
+ break;
+ default:
+ BLI_snprintf(msg, sizeof(msg), "%s", ui_name); /* XXX: No value? */
+ break;
}
- ED_area_headerprint(sa, msg);
}
+
+ ED_area_status_text(sa, msg);
}
static void radial_control_set_initial_mouse(RadialControl *rc, const wmEvent *event)
@@ -1949,8 +2064,9 @@ static void radial_control_set_tex(RadialControl *rc)
if ((ibuf = BKE_brush_gen_radial_control_imbuf(rc->image_id_ptr.data, rc->use_secondary_tex))) {
glGenTextures(1, &rc->gltex);
glBindTexture(GL_TEXTURE_2D, rc->gltex);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA8, ibuf->x, ibuf->y, 0,
- GL_ALPHA, GL_FLOAT, ibuf->rect_float);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, ibuf->x, ibuf->y, 0,
+ GL_RED, GL_FLOAT, ibuf->rect_float);
+ glBindTexture(GL_TEXTURE_2D, 0);
MEM_freeN(ibuf->rect_float);
MEM_freeN(ibuf);
}
@@ -1983,49 +2099,69 @@ static void radial_control_paint_tex(RadialControl *rc, float radius, float alph
RNA_property_float_get_array(fill_ptr, fill_prop, col);
}
- glColor4f(col[0], col[1], col[2], alpha);
+
+ Gwn_VertFormat *format = immVertexFormat();
+ uint pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
if (rc->gltex) {
+
+ uint texCoord = GWN_vertformat_attr_add(format, "texCoord", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+
+ glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, rc->gltex);
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
+ GLint swizzleMask[] = {GL_ZERO, GL_ZERO, GL_ZERO, GL_RED};
+ glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_RGBA, swizzleMask);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_IMAGE_MASK_UNIFORM_COLOR);
+
+ immUniformColor3fvAlpha(col, alpha);
+ immUniform1i("image", 0);
/* set up rotation if available */
if (rc->rot_prop) {
rot = RNA_property_float_get(&rc->rot_ptr, rc->rot_prop);
- glPushMatrix();
- glRotatef(RAD2DEGF(rot), 0, 0, 1);
+ gpuPushMatrix();
+ gpuRotate2D(RAD2DEGF(rot));
}
/* draw textured quad */
- GPU_basic_shader_bind(GPU_SHADER_TEXTURE_2D | GPU_SHADER_USE_COLOR);
- glBegin(GL_QUADS);
- glTexCoord2f(0, 0);
- glVertex2f(-radius, -radius);
- glTexCoord2f(1, 0);
- glVertex2f(radius, -radius);
- glTexCoord2f(1, 1);
- glVertex2f(radius, radius);
- glTexCoord2f(0, 1);
- glVertex2f(-radius, radius);
- glEnd();
- GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
+ immBegin(GWN_PRIM_TRI_FAN, 4);
+
+ immAttrib2f(texCoord, 0, 0);
+ immVertex2f(pos, -radius, -radius);
+
+ immAttrib2f(texCoord, 1, 0);
+ immVertex2f(pos, radius, -radius);
+
+ immAttrib2f(texCoord, 1, 1);
+ immVertex2f(pos, radius, radius);
+
+ immAttrib2f(texCoord, 0, 1);
+ immVertex2f(pos, -radius, radius);
+
+ immEnd();
/* undo rotation */
if (rc->rot_prop)
- glPopMatrix();
+ gpuPopMatrix();
}
else {
/* flat color if no texture available */
- glutil_draw_filled_arc(0, M_PI * 2, radius, 40);
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformColor3fvAlpha(col, alpha);
+ imm_draw_circle_fill_2d(pos, 0.0f, 0.0f, radius, 40);
}
+
+ immUnbindProgram();
}
-static void radial_control_paint_cursor(bContext *C, int x, int y, void *customdata)
+static void radial_control_paint_cursor(bContext *UNUSED(C), int x, int y, void *customdata)
{
RadialControl *rc = customdata;
- ARegion *ar = CTX_wm_region(C);
uiStyle *style = UI_style_get();
const uiFontStyle *fstyle = &style->widget;
const int fontid = fstyle->uifont_id;
@@ -2076,9 +2212,9 @@ static void radial_control_paint_cursor(bContext *C, int x, int y, void *customd
}
/* Keep cursor in the original place */
- x = rc->initial_mouse[0] - ar->winrct.xmin;
- y = rc->initial_mouse[1] - ar->winrct.ymin;
- glTranslatef((float)x, (float)y, 0.0f);
+ x = rc->initial_mouse[0];
+ y = rc->initial_mouse[1];
+ gpuTranslate2f((float)x, (float)y);
glEnable(GL_BLEND);
glEnable(GL_LINE_SMOOTH);
@@ -2086,7 +2222,7 @@ static void radial_control_paint_cursor(bContext *C, int x, int y, void *customd
/* apply zoom if available */
if (rc->zoom_prop) {
RNA_property_float_get_array(&rc->zoom_ptr, rc->zoom_prop, zoom);
- glScalef(zoom[0], zoom[1], 1);
+ gpuScale2fv(zoom);
}
/* draw rotated texture */
@@ -2095,24 +2231,39 @@ static void radial_control_paint_cursor(bContext *C, int x, int y, void *customd
/* set line color */
if (rc->col_prop)
RNA_property_float_get_array(&rc->col_ptr, rc->col_prop, col);
- glColor4f(col[0], col[1], col[2], 0.5);
+
+ Gwn_VertFormat *format = immVertexFormat();
+ uint pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformColor3fvAlpha(col, 0.5f);
if (rc->subtype == PROP_ANGLE) {
- glPushMatrix();
+ gpuPushMatrix();
+
/* draw original angle line */
- glRotatef(RAD2DEGF(rc->initial_value), 0, 0, 1);
- fdrawline((float)WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE, 0.0f, (float)WM_RADIAL_CONTROL_DISPLAY_SIZE, 0.0f);
+ gpuRotate2D(RAD2DEGF(rc->initial_value));
+ immBegin(GWN_PRIM_LINES, 2);
+ immVertex2f(pos, (float)WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE, 0.0f);
+ immVertex2f(pos, (float)WM_RADIAL_CONTROL_DISPLAY_SIZE, 0.0f);
+ immEnd();
+
/* draw new angle line */
- glRotatef(RAD2DEGF(rc->current_value - rc->initial_value), 0, 0, 1);
- fdrawline((float)WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE, 0.0f, (float)WM_RADIAL_CONTROL_DISPLAY_SIZE, 0.0f);
- glPopMatrix();
+ gpuRotate2D(RAD2DEGF(rc->current_value - rc->initial_value));
+ immBegin(GWN_PRIM_LINES, 2);
+ immVertex2f(pos, (float)WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE, 0.0f);
+ immVertex2f(pos, (float)WM_RADIAL_CONTROL_DISPLAY_SIZE, 0.0f);
+ immEnd();
+
+ gpuPopMatrix();
}
/* draw circles on top */
- glutil_draw_lined_arc(0.0, (float)(M_PI * 2.0), r1, 40);
- glutil_draw_lined_arc(0.0, (float)(M_PI * 2.0), r2, 40);
+ imm_draw_circle_wire_2d(pos, 0.0f, 0.0f, r1, 40);
+ imm_draw_circle_wire_2d(pos, 0.0f, 0.0f, r2, 40);
if (rmin > 0.0f)
- glutil_draw_lined_arc(0.0, (float)(M_PI * 2.0), rmin, 40);
+ imm_draw_circle_wire_2d(pos, 0.0, 0.0f, rmin, 40);
+ immUnbindProgram();
BLF_size(fontid, 1.5 * fstyle_points * U.pixelsize, U.dpi);
BLF_enable(fontid, BLF_SHADOW);
@@ -2128,6 +2279,7 @@ static void radial_control_paint_cursor(bContext *C, int x, int y, void *customd
glDisable(GL_BLEND);
glDisable(GL_LINE_SMOOTH);
+
}
typedef enum {
@@ -2396,9 +2548,7 @@ static void radial_control_cancel(bContext *C, wmOperator *op)
rc->dial = NULL;
}
- if (sa) {
- ED_area_headerprint(sa, NULL);
- }
+ ED_area_status_text(sa, NULL);
WM_paint_cursor_end(wm, rc->cursor);
@@ -2700,6 +2850,7 @@ static const EnumPropertyItem redraw_timer_type_items[] = {
static void redraw_timer_step(
bContext *C, Main *bmain, Scene *scene,
+ struct Depsgraph *depsgraph,
wmWindow *win, ScrArea *sa, ARegion *ar,
const int type, const int cfra)
{
@@ -2718,16 +2869,17 @@ static void redraw_timer_step(
CTX_wm_window_set(C, win); /* XXX context manipulation warning! */
}
else if (type == eRTDrawWindow) {
+ bScreen *screen = WM_window_get_active_screen(win);
ScrArea *sa_iter;
CTX_wm_menu_set(C, NULL);
- for (sa_iter = win->screen->areabase.first; sa_iter; sa_iter = sa_iter->next) {
+ for (sa_iter = screen->areabase.first; sa_iter; sa_iter = sa_iter->next) {
ARegion *ar_iter;
CTX_wm_area_set(C, sa_iter);
for (ar_iter = sa_iter->regionbase.first; ar_iter; ar_iter = ar_iter->next) {
- if (ar_iter->swinid) {
+ if (ar_iter->visible) {
CTX_wm_region_set(C, ar_iter);
ED_region_do_draw(C, ar_iter);
ar_iter->do_draw = false;
@@ -2745,7 +2897,7 @@ static void redraw_timer_step(
}
else if (type == eRTAnimationStep) {
scene->r.cfra += (cfra == scene->r.cfra) ? 1 : -1;
- BKE_scene_update_for_newframe(bmain->eval_ctx, bmain, scene, scene->lay);
+ BKE_scene_graph_update_for_newframe(depsgraph, bmain);
}
else if (type == eRTAnimationPlay) {
/* play anim, return on same frame as started with */
@@ -2757,7 +2909,7 @@ static void redraw_timer_step(
if (scene->r.cfra > scene->r.efra)
scene->r.cfra = scene->r.sfra;
- BKE_scene_update_for_newframe(bmain->eval_ctx, bmain, scene, scene->lay);
+ BKE_scene_graph_update_for_newframe(depsgraph, bmain);
redraw_timer_window_swap(C);
}
}
@@ -2781,13 +2933,14 @@ static int redraw_timer_exec(bContext *C, wmOperator *op)
const int cfra = scene->r.cfra;
int a, iter_steps = 0;
const char *infostr = "";
+ struct Depsgraph *depsgraph = CTX_data_depsgraph(C);
WM_cursor_wait(1);
time_start = PIL_check_seconds_timer();
for (a = 0; a < iter; a++) {
- redraw_timer_step(C, bmain, scene, win, sa, ar, type, cfra);
+ redraw_timer_step(C, bmain, scene, depsgraph, win, sa, ar, type, cfra);
iter_steps += 1;
if (time_limit != 0.0) {
@@ -2845,28 +2998,6 @@ static void WM_OT_memory_statistics(wmOperatorType *ot)
ot->exec = memory_statistics_exec;
}
-/* ************************** memory statistics for testing ***************** */
-
-static int dependency_relations_exec(bContext *C, wmOperator *UNUSED(op))
-{
- Main *bmain = CTX_data_main(C);
- Scene *scene = CTX_data_scene(C);
- Object *ob = CTX_data_active_object(C);
-
- DAG_print_dependencies(bmain, scene, ob);
-
- return OPERATOR_FINISHED;
-}
-
-static void WM_OT_dependency_relations(wmOperatorType *ot)
-{
- ot->name = "Dependency Relations";
- ot->idname = "WM_OT_dependency_relations";
- ot->description = "Print dependency graph relations to the console";
-
- ot->exec = dependency_relations_exec;
-}
-
/* *************************** Mat/tex/etc. previews generation ************* */
typedef struct PreviewsIDEnsureData {
@@ -2959,7 +3090,7 @@ static const EnumPropertyItem preview_id_type_items[] = {
{FILTER_ID_GR, "GROUP", 0, "Groups", ""},
{FILTER_ID_OB, "OBJECT", 0, "Objects", ""},
{FILTER_ID_MA, "MATERIAL", 0, "Materials", ""},
- {FILTER_ID_LA, "LAMP", 0, "Lamps", ""},
+ {FILTER_ID_LA, "LIGHT", 0, "Lights", ""},
{FILTER_ID_WO, "WORLD", 0, "Worlds", ""},
{FILTER_ID_TE, "TEXTURE", 0, "Textures", ""},
{FILTER_ID_IM, "IMAGE", 0, "Images", ""},
@@ -2972,7 +3103,7 @@ static const EnumPropertyItem preview_id_type_items[] = {
static int previews_clear_exec(bContext *C, wmOperator *op)
{
Main *bmain = CTX_data_main(C);
- ListBase *lb[] = {&bmain->object, &bmain->group,
+ ListBase *lb[] = {&bmain->object, &bmain->collection,
&bmain->mat, &bmain->world, &bmain->lamp, &bmain->tex, &bmain->image, NULL};
int i;
@@ -3050,8 +3181,6 @@ static void WM_OT_doc_view_manual_ui_context(wmOperatorType *ot)
}
/* ******************************************************* */
-
-/* ******************************************************* */
/* toggle 3D for current window, turning it fullscreen if needed */
static void WM_OT_stereo3d_set(wmOperatorType *ot)
{
@@ -3085,12 +3214,14 @@ static void WM_OT_stereo3d_set(wmOperatorType *ot)
void wm_operatortypes_register(void)
{
WM_operatortype_append(WM_OT_window_close);
- WM_operatortype_append(WM_OT_window_duplicate);
+ WM_operatortype_append(WM_OT_window_new);
+ WM_operatortype_append(WM_OT_window_new_main);
WM_operatortype_append(WM_OT_read_history);
WM_operatortype_append(WM_OT_read_homefile);
WM_operatortype_append(WM_OT_read_factory_settings);
WM_operatortype_append(WM_OT_save_homefile);
WM_operatortype_append(WM_OT_save_userpref);
+ WM_operatortype_append(WM_OT_save_workspace_file);
WM_operatortype_append(WM_OT_userpref_autoexec_path_add);
WM_operatortype_append(WM_OT_userpref_autoexec_path_remove);
WM_operatortype_append(WM_OT_window_fullscreen_toggle);
@@ -3107,13 +3238,13 @@ void wm_operatortypes_register(void)
WM_operatortype_append(WM_OT_save_mainfile);
WM_operatortype_append(WM_OT_redraw_timer);
WM_operatortype_append(WM_OT_memory_statistics);
- WM_operatortype_append(WM_OT_dependency_relations);
WM_operatortype_append(WM_OT_debug_menu);
WM_operatortype_append(WM_OT_operator_defaults);
WM_operatortype_append(WM_OT_splash);
WM_operatortype_append(WM_OT_search_menu);
WM_operatortype_append(WM_OT_call_menu);
WM_operatortype_append(WM_OT_call_menu_pie);
+ WM_operatortype_append(WM_OT_call_panel);
WM_operatortype_append(WM_OT_radial_control);
WM_operatortype_append(WM_OT_stereo3d_set);
#if defined(WIN32)
@@ -3122,6 +3253,10 @@ void wm_operatortypes_register(void)
WM_operatortype_append(WM_OT_previews_ensure);
WM_operatortype_append(WM_OT_previews_clear);
WM_operatortype_append(WM_OT_doc_view_manual_ui_context);
+
+ /* manipulators */
+ WM_operatortype_append(MANIPULATORGROUP_OT_manipulator_select);
+ WM_operatortype_append(MANIPULATORGROUP_OT_manipulator_tweak);
}
/* circleselect-like modal operators */
@@ -3324,7 +3459,10 @@ void wm_window_keymap(wmKeyConfig *keyconf)
wmKeyMapItem *kmi;
/* note, this doesn't replace existing keymap items */
- WM_keymap_verify_item(keymap, "WM_OT_window_duplicate", WKEY, KM_PRESS, KM_CTRL | KM_ALT, 0);
+#ifdef USE_WM_KEYMAP_27X
+ WM_keymap_verify_item(keymap, "WM_OT_window_new", WKEY, KM_PRESS, KM_CTRL | KM_ALT, 0);
+#endif
+
#ifdef __APPLE__
WM_keymap_add_item(keymap, "WM_OT_read_homefile", NKEY, KM_PRESS, KM_OSKEY, 0);
WM_keymap_add_menu(keymap, "INFO_MT_file_open_recent", OKEY, KM_PRESS, KM_SHIFT | KM_OSKEY, 0);
@@ -3334,40 +3472,60 @@ void wm_window_keymap(wmKeyConfig *keyconf)
WM_keymap_add_item(keymap, "WM_OT_quit_blender", QKEY, KM_PRESS, KM_OSKEY, 0);
#endif
WM_keymap_add_item(keymap, "WM_OT_read_homefile", NKEY, KM_PRESS, KM_CTRL, 0);
+#ifdef USE_WM_KEYMAP_27X
WM_keymap_add_item(keymap, "WM_OT_save_homefile", UKEY, KM_PRESS, KM_CTRL, 0);
+#endif
WM_keymap_add_menu(keymap, "INFO_MT_file_open_recent", OKEY, KM_PRESS, KM_SHIFT | KM_CTRL, 0);
WM_keymap_add_item(keymap, "WM_OT_open_mainfile", OKEY, KM_PRESS, KM_CTRL, 0);
+#ifdef USE_WM_KEYMAP_27X
WM_keymap_add_item(keymap, "WM_OT_open_mainfile", F1KEY, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "WM_OT_link", OKEY, KM_PRESS, KM_CTRL | KM_ALT, 0);
WM_keymap_add_item(keymap, "WM_OT_append", F1KEY, KM_PRESS, KM_SHIFT, 0);
+#endif
WM_keymap_add_item(keymap, "WM_OT_save_mainfile", SKEY, KM_PRESS, KM_CTRL, 0);
+#ifdef USE_WM_KEYMAP_27X
WM_keymap_add_item(keymap, "WM_OT_save_mainfile", WKEY, KM_PRESS, KM_CTRL, 0);
+#endif
WM_keymap_add_item(keymap, "WM_OT_save_as_mainfile", SKEY, KM_PRESS, KM_SHIFT | KM_CTRL, 0);
+#ifdef USE_WM_KEYMAP_27X
WM_keymap_add_item(keymap, "WM_OT_save_as_mainfile", F2KEY, KM_PRESS, 0, 0);
kmi = WM_keymap_add_item(keymap, "WM_OT_save_as_mainfile", SKEY, KM_PRESS, KM_ALT | KM_CTRL, 0);
RNA_boolean_set(kmi->ptr, "copy", true);
WM_keymap_verify_item(keymap, "WM_OT_window_fullscreen_toggle", F11KEY, KM_PRESS, KM_ALT, 0);
+#endif
+
WM_keymap_add_item(keymap, "WM_OT_quit_blender", QKEY, KM_PRESS, KM_CTRL, 0);
+ /* F-Keys are a hassle on some macos systems. */
+#ifdef __APPLE__
+ WM_keymap_add_item(keymap, "WM_OT_search_menu", FKEY, KM_PRESS, KM_OSKEY, 0);
+#endif
+
+#ifdef USE_WM_KEYMAP_27X
WM_keymap_add_item(keymap, "WM_OT_doc_view_manual_ui_context", F1KEY, KM_PRESS, KM_ALT, 0);
/* debug/testing */
WM_keymap_verify_item(keymap, "WM_OT_redraw_timer", TKEY, KM_PRESS, KM_ALT | KM_CTRL, 0);
WM_keymap_verify_item(keymap, "WM_OT_debug_menu", DKEY, KM_PRESS, KM_ALT | KM_CTRL, 0);
+#else
+ WM_keymap_add_item(keymap, "WM_OT_doc_view_manual_ui_context", F1KEY, KM_PRESS, 0, 0);
+ WM_keymap_add_menu(keymap, "TOPBAR_MT_file_specials", F2KEY, KM_PRESS, 0, 0);
+ WM_keymap_add_item(keymap, "WM_OT_search_menu", F3KEY, KM_PRESS, 0, 0);
+ WM_keymap_add_menu(keymap, "TOPBAR_MT_window_specials", F4KEY, KM_PRESS, 0, 0);
+#endif
/* menus that can be accessed anywhere in blender */
- WM_keymap_verify_item(keymap, "WM_OT_search_menu", SPACEKEY, KM_PRESS, 0, 0);
+ WM_keymap_add_menu(keymap, "SCREEN_MT_user_menu", QKEY, KM_PRESS, 0, 0);
+
#ifdef WITH_INPUT_NDOF
WM_keymap_add_menu(keymap, "USERPREF_MT_ndof_settings", NDOF_BUTTON_MENU, KM_PRESS, 0, 0);
#endif
- /* Space switching */
- kmi = WM_keymap_add_item(keymap, "WM_OT_context_set_enum", F2KEY, KM_PRESS, KM_SHIFT, 0); /* new in 2.5x, was DXF export */
- RNA_string_set(kmi->ptr, "data_path", "area.type");
- RNA_string_set(kmi->ptr, "value", "LOGIC_EDITOR");
+ WM_keymap_add_item(keymap, "WM_OT_toolbar", SPACEKEY, KM_PRESS, 0, 0);
+ /* Space switching */
kmi = WM_keymap_add_item(keymap, "WM_OT_context_set_enum", F3KEY, KM_PRESS, KM_SHIFT, 0);
RNA_string_set(kmi->ptr, "data_path", "area.type");
RNA_string_set(kmi->ptr, "value", "NODE_EDITOR");
@@ -3428,6 +3586,7 @@ void wm_window_keymap(wmKeyConfig *keyconf)
RNA_float_set(kmi->ptr, "value", 1.0f / 1.5f);
#endif /* WITH_INPUT_NDOF */
+ wm_manipulators_keymap(keyconf);
gesture_circle_modal_keymap(keyconf);
gesture_border_modal_keymap(keyconf);
gesture_zoom_border_modal_keymap(keyconf);
@@ -3483,13 +3642,13 @@ const EnumPropertyItem *RNA_action_local_itemf(bContext *C, PointerRNA *ptr, Pro
}
#endif
-const EnumPropertyItem *RNA_group_itemf(bContext *C, PointerRNA *ptr, PropertyRNA *UNUSED(prop), bool *r_free)
+const EnumPropertyItem *RNA_collection_itemf(bContext *C, PointerRNA *ptr, PropertyRNA *UNUSED(prop), bool *r_free)
{
- return rna_id_itemf(C, ptr, r_free, C ? (ID *)CTX_data_main(C)->group.first : NULL, false, NULL, NULL);
+ return rna_id_itemf(C, ptr, r_free, C ? (ID *)CTX_data_main(C)->collection.first : NULL, false, NULL, NULL);
}
-const EnumPropertyItem *RNA_group_local_itemf(bContext *C, PointerRNA *ptr, PropertyRNA *UNUSED(prop), bool *r_free)
+const EnumPropertyItem *RNA_collection_local_itemf(bContext *C, PointerRNA *ptr, PropertyRNA *UNUSED(prop), bool *r_free)
{
- return rna_id_itemf(C, ptr, r_free, C ? (ID *)CTX_data_main(C)->group.first : NULL, true, NULL, NULL);
+ return rna_id_itemf(C, ptr, r_free, C ? (ID *)CTX_data_main(C)->collection.first : NULL, true, NULL, NULL);
}
const EnumPropertyItem *RNA_image_itemf(bContext *C, PointerRNA *ptr, PropertyRNA *UNUSED(prop), bool *r_free)
diff --git a/source/blender/windowmanager/intern/wm_playanim.c b/source/blender/windowmanager/intern/wm_playanim.c
index b4f2435ee2d..003932930ed 100644
--- a/source/blender/windowmanager/intern/wm_playanim.c
+++ b/source/blender/windowmanager/intern/wm_playanim.c
@@ -58,24 +58,31 @@
#include "IMB_imbuf_types.h"
#include "IMB_imbuf.h"
-#include "BKE_depsgraph.h"
#include "BKE_image.h"
#include "BIF_gl.h"
#include "BIF_glutil.h"
+#include "GPU_matrix.h"
+#include "GPU_immediate.h"
+#include "GPU_immediate_util.h"
+#include "GPU_batch.h"
+#include "GPU_init_exit.h"
+
#include "DNA_scene_types.h"
#include "ED_datafiles.h" /* for fonts */
#include "GHOST_C-api.h"
#include "BLF_api.h"
+#include "DEG_depsgraph.h"
+
#include "WM_api.h" /* only for WM_main_playanim */
#ifdef WITH_AUDASPACE
-# include AUD_DEVICE_H
-# include AUD_HANDLE_H
-# include AUD_SOUND_H
-# include AUD_SPECIAL_H
+# include <AUD_Device.h>
+# include <AUD_Handle.h>
+# include <AUD_Sound.h>
+# include <AUD_Special.h>
static AUD_Sound *source = NULL;
static AUD_Handle *playback_handle = NULL;
@@ -177,6 +184,7 @@ typedef enum eWS_Qual {
static struct WindowStateGlobal {
GHOST_SystemHandle ghost_system;
void *ghost_window;
+ Gwn_Context *gwn_context;
/* events */
eWS_Qual qual;
@@ -193,10 +201,8 @@ static void playanim_window_get_size(int *r_width, int *r_height)
static void playanim_gl_matrix(void)
{
/* unified matrix, note it affects offset for drawing */
- glMatrixMode(GL_PROJECTION);
- glLoadIdentity();
- glOrtho(0.0f, 1.0f, 0.0f, 1.0f, -1.0f, 1.0f);
- glMatrixMode(GL_MODELVIEW);
+ /* note! cannot use gpuOrtho2D here because shader ignores. */
+ gpuOrtho(0.0f, 1.0f, 0.0f, 1.0f, -1.0, 1.0f);
}
/* implementation */
@@ -311,7 +317,6 @@ static void playanim_toscreen(PlayState *ps, PlayAnimPict *picture, struct ImBuf
CLAMP(offs_x, 0.0f, 1.0f);
CLAMP(offs_y, 0.0f, 1.0f);
- glRasterPos2f(offs_x, offs_y);
glClearColor(0.1, 0.1, 0.1, 0.0);
glClear(GL_COLOR_BUFFER_BIT);
@@ -319,18 +324,22 @@ static void playanim_toscreen(PlayState *ps, PlayAnimPict *picture, struct ImBuf
/* checkerboard for case alpha */
if (ibuf->planes == 32) {
glEnable(GL_BLEND);
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
- fdrawcheckerboard(offs_x, offs_y, offs_x + span_x, offs_y + span_y);
+ imm_draw_box_checker_2d(offs_x, offs_y, offs_x + span_x, offs_y + span_y);
}
- glRasterPos2f(offs_x + (ps->draw_flip[0] ? span_x : 0.0f),
- offs_y + (ps->draw_flip[1] ? span_y : 0.0f));
+ IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_COLOR);
- glPixelZoom(ps->zoom * (ps->draw_flip[0] ? -1.0f : 1.0f),
- ps->zoom * (ps->draw_flip[1] ? -1.0f : 1.0f));
-
- glDrawPixels(ibuf->x, ibuf->y, GL_RGBA, GL_UNSIGNED_BYTE, ibuf->rect);
+ immDrawPixelsTex(
+ &state,
+ offs_x + (ps->draw_flip[0] ? span_x : 0.0f),
+ offs_y + (ps->draw_flip[1] ? span_y : 0.0f),
+ ibuf->x, ibuf->y, GL_RGBA, GL_UNSIGNED_BYTE, GL_NEAREST,
+ ibuf->rect,
+ ((ps->draw_flip[0] ? -1.0f : 1.0f)) * (ps->zoom / (float)ps->win_x),
+ ((ps->draw_flip[1] ? -1.0f : 1.0f)) * (ps->zoom / (float)ps->win_y),
+ NULL);
glDisable(GL_BLEND);
@@ -340,13 +349,13 @@ static void playanim_toscreen(PlayState *ps, PlayAnimPict *picture, struct ImBuf
int sizex, sizey;
float fsizex_inv, fsizey_inv;
char str[32 + FILE_MAX];
- cpack(-1);
BLI_snprintf(str, sizeof(str), "%s | %.2f frames/s", picture->name, fstep / swaptime);
playanim_window_get_size(&sizex, &sizey);
fsizex_inv = 1.0f / sizex;
fsizey_inv = 1.0f / sizey;
+ BLF_color4f(fontid, 1.0, 1.0, 1.0, 1.0);
BLF_enable(fontid, BLF_ASPECT);
BLF_aspect(fontid, fsizex_inv, fsizey_inv, 1.0f);
BLF_position(fontid, 10.0f * fsizex_inv, 10.0f * fsizey_inv, 0.0f);
@@ -357,24 +366,25 @@ static void playanim_toscreen(PlayState *ps, PlayAnimPict *picture, struct ImBuf
float fac = ps->picture->frame / (double)(((PlayAnimPict *)picsbase.last)->frame - ((PlayAnimPict *)picsbase.first)->frame);
fac = 2.0f * fac - 1.0f;
- glMatrixMode(GL_PROJECTION);
- glPushMatrix();
- glLoadIdentity();
- glMatrixMode(GL_MODELVIEW);
- glPushMatrix();
- glLoadIdentity();
-
- glColor4f(0.0f, 1.0f, 0.0f, 1.0f);
-
- glBegin(GL_LINES);
- glVertex2f(fac, -1.0f);
- glVertex2f(fac, 1.0f);
- glEnd();
-
- glPopMatrix();
- glMatrixMode(GL_PROJECTION);
- glPopMatrix();
- glMatrixMode(GL_MODELVIEW);
+ gpuPushProjectionMatrix();
+ gpuLoadIdentityProjectionMatrix();
+ gpuPushMatrix();
+ gpuLoadIdentity();
+
+ uint pos = GWN_vertformat_attr_add(immVertexFormat(), "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
+ immUniformColor3ub(0, 255, 0);
+
+ immBegin(GWN_PRIM_LINES, 2);
+ immVertex2f(pos, fac, -1.0f);
+ immVertex2f(pos, fac, 1.0f);
+ immEnd();
+
+ immUnbindProgram();
+
+ gpuPopMatrix();
+ gpuPopProjectionMatrix();
}
GHOST_SwapWindowBuffers(g_WS.ghost_window);
@@ -1270,6 +1280,11 @@ static char *wm_main_playanim_intern(int argc, const char **argv)
//GHOST_ActivateWindowDrawingContext(g_WS.ghost_window);
+ /* initialize OpenGL immediate mode */
+ g_WS.gwn_context = GWN_context_create();
+ GPU_init();
+ immActivate();
+
/* initialize the font */
BLF_init();
ps.fontid = BLF_load_mem("monospace", (unsigned char *)datatoc_bmonofont_ttf, datatoc_bmonofont_ttf_size);
@@ -1535,8 +1550,19 @@ static char *wm_main_playanim_intern(int argc, const char **argv)
/* we still miss freeing a lot!,
* but many areas could skip initialization too for anim play */
+ GPU_shader_free_builtin_shaders();
+
+ if (g_WS.gwn_context) {
+ GWN_context_active_set(g_WS.gwn_context);
+ GWN_context_discard(g_WS.gwn_context);
+ g_WS.gwn_context = NULL;
+ }
+
BLF_exit();
+ immDeactivate();
+ GPU_exit();
+
GHOST_DisposeWindow(g_WS.ghost_system, g_WS.ghost_window);
/* early exit, IMB and BKE should be exited only in end */
@@ -1547,7 +1573,7 @@ static char *wm_main_playanim_intern(int argc, const char **argv)
IMB_exit();
BKE_images_exit();
- DAG_exit();
+ DEG_free_node_types();
totblock = MEM_get_memory_blocks_in_use();
if (totblock != 0) {
diff --git a/source/blender/windowmanager/intern/wm_stereo.c b/source/blender/windowmanager/intern/wm_stereo.c
index 55fe2ec846c..1e9f6d6231b 100644
--- a/source/blender/windowmanager/intern/wm_stereo.c
+++ b/source/blender/windowmanager/intern/wm_stereo.c
@@ -52,90 +52,86 @@
#include "ED_screen.h"
-#include "GPU_glew.h"
-#include "GPU_basic_shader.h"
+#include "GPU_immediate.h"
+#include "GPU_framebuffer.h"
+#include "GPU_texture.h"
#include "WM_api.h"
#include "WM_types.h"
#include "wm.h"
-#include "wm_draw.h" /* wmDrawTriple */
+#include "wm_draw.h"
#include "wm_window.h"
#include "UI_interface.h"
#include "UI_resources.h"
-static void wm_method_draw_stereo3d_pageflip(wmWindow *win)
+static GPUInterlaceShader interlace_gpu_id_from_type(eStereo3dInterlaceType interlace_type)
{
- wmDrawData *drawdata;
- int view;
+ switch (interlace_type) {
+ case S3D_INTERLACE_ROW:
+ return GPU_SHADER_INTERLACE_ROW;
+ case S3D_INTERLACE_COLUMN:
+ return GPU_SHADER_INTERLACE_COLUMN;
+ case S3D_INTERLACE_CHECKERBOARD:
+ default:
+ return GPU_SHADER_INTERLACE_CHECKER;
+ }
+}
+
+void wm_stereo3d_draw_interlace(wmWindow *win, ARegion *ar)
+{
+ bool swap = (win->stereo3d_format->flag & S3D_INTERLACE_SWAP) != 0;
+ enum eStereo3dInterlaceType interlace_type = win->stereo3d_format->interlace_type;
- for (view = 0; view < 2; view ++) {
- drawdata = BLI_findlink(&win->drawdata, (view * 2) + 1);
+ /* wmOrtho for the screen has this same offset */
+ float halfx = GLA_PIXEL_OFS / ar->winx;
+ float halfy = GLA_PIXEL_OFS / ar->winy;
- if (view == STEREO_LEFT_ID)
- glDrawBuffer(GL_BACK_LEFT);
- else //STEREO_RIGHT_ID
- glDrawBuffer(GL_BACK_RIGHT);
+ Gwn_VertFormat *format = immVertexFormat();
+ uint texcoord = GWN_vertformat_attr_add(format, "texCoord", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ uint pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
- wm_triple_draw_textures(win, drawdata->triple, 1.0f, false);
+ /* leave GL_TEXTURE0 as the latest active texture */
+ for (int view = 1; view >= 0; view--) {
+ GPUTexture *texture = wm_draw_region_texture(ar, view);
+ glActiveTexture(GL_TEXTURE0 + view);
+ glBindTexture(GL_TEXTURE_2D, GPU_texture_opengl_bindcode(texture));
}
- glDrawBuffer(GL_BACK);
-}
+ immBindBuiltinProgram(GPU_SHADER_2D_IMAGE_INTERLACE);
+ immUniform1i("image_a", (swap) ? 1 : 0);
+ immUniform1i("image_b", (swap) ? 0 : 1);
-static enum eStereo3dInterlaceType interlace_prev_type = -1;
-static char interlace_prev_swap = -1;
+ immUniform1i("interlace_id", interlace_gpu_id_from_type(interlace_type));
-static void wm_method_draw_stereo3d_interlace(wmWindow *win)
-{
- wmDrawData *drawdata;
- int view;
- bool flag;
- bool swap = (win->stereo3d_format->flag & S3D_INTERLACE_SWAP) != 0;
- enum eStereo3dInterlaceType interlace_type = win->stereo3d_format->interlace_type;
+ immBegin(GWN_PRIM_TRI_FAN, 4);
- for (view = 0; view < 2; view ++) {
- flag = swap ? !view : view;
- drawdata = BLI_findlink(&win->drawdata, (view * 2) + 1);
- GPU_basic_shader_bind(GPU_SHADER_STIPPLE);
- switch (interlace_type) {
- case S3D_INTERLACE_ROW:
- if (flag)
- GPU_basic_shader_stipple(GPU_SHADER_STIPPLE_S3D_INTERLACE_ROW_SWAP);
- else
- GPU_basic_shader_stipple(GPU_SHADER_STIPPLE_S3D_INTERLACE_ROW);
- break;
- case S3D_INTERLACE_COLUMN:
- if (flag)
- GPU_basic_shader_stipple(GPU_SHADER_STIPPLE_S3D_INTERLACE_COLUMN_SWAP);
- else
- GPU_basic_shader_stipple(GPU_SHADER_STIPPLE_S3D_INTERLACE_COLUMN);
- break;
- case S3D_INTERLACE_CHECKERBOARD:
- default:
- if (flag)
- GPU_basic_shader_stipple(GPU_SHADER_STIPPLE_S3D_INTERLACE_CHECKER_SWAP);
- else
- GPU_basic_shader_stipple(GPU_SHADER_STIPPLE_S3D_INTERLACE_CHECKER);
- break;
- }
+ immAttrib2f(texcoord, halfx, halfy);
+ immVertex2f(pos, ar->winrct.xmin, ar->winrct.ymin);
- wm_triple_draw_textures(win, drawdata->triple, 1.0f, true);
- GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
+ immAttrib2f(texcoord, 1.0f + halfx, halfy);
+ immVertex2f(pos, ar->winrct.xmax + 1, ar->winrct.ymin);
+
+ immAttrib2f(texcoord, 1.0f + halfx, 1.0f + halfy);
+ immVertex2f(pos, ar->winrct.xmax + 1, ar->winrct.ymax + 1);
+
+ immAttrib2f(texcoord, halfx, 1.0f + halfy);
+ immVertex2f(pos, ar->winrct.xmin, ar->winrct.ymax + 1);
+
+ immEnd();
+ immUnbindProgram();
+
+ for (int view = 1; view >= 0; view--) {
+ glActiveTexture(GL_TEXTURE0 + view);
+ glBindTexture(GL_TEXTURE_2D, 0);
}
- interlace_prev_type = interlace_type;
- interlace_prev_swap = swap;
}
-static void wm_method_draw_stereo3d_anaglyph(wmWindow *win)
+void wm_stereo3d_draw_anaglyph(wmWindow *win, ARegion *ar)
{
- wmDrawData *drawdata;
- int view, bit;
+ for (int view = 0; view < 2; view ++) {
+ int bit = view + 1;
- for (view = 0; view < 2; view ++) {
- drawdata = BLI_findlink(&win->drawdata, (view * 2) + 1);
-
- bit = view + 1;
switch (win->stereo3d_format->anaglyph_type) {
case S3D_ANAGLYPH_REDCYAN:
glColorMask((1&bit) ? GL_TRUE : GL_FALSE,
@@ -157,162 +153,110 @@ static void wm_method_draw_stereo3d_anaglyph(wmWindow *win)
break;
}
- wm_triple_draw_textures(win, drawdata->triple, 1.0f, false);
-
- glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
+ wm_draw_region_blend(ar, view, false);
}
+
+ glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
}
-static void wm_method_draw_stereo3d_sidebyside(wmWindow *win)
+void wm_stereo3d_draw_sidebyside(wmWindow *win, int view)
{
- wmDrawData *drawdata;
- wmDrawTriple *triple;
- float halfx, halfy, ratiox, ratioy;
- int view;
- int soffx;
bool cross_eyed = (win->stereo3d_format->flag & S3D_SIDEBYSIDE_CROSSEYED) != 0;
- for (view = 0; view < 2; view ++) {
- drawdata = BLI_findlink(&win->drawdata, (view * 2) + 1);
- triple = drawdata->triple;
+ Gwn_VertFormat *format = immVertexFormat();
+ uint texcoord = GWN_vertformat_attr_add(format, "texCoord", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ uint pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
- soffx = WM_window_pixels_x(win) * 0.5f;
- if (view == STEREO_LEFT_ID) {
- if (!cross_eyed)
- soffx = 0;
- }
- else { //RIGHT_LEFT_ID
- if (cross_eyed)
- soffx = 0;
- }
+ immBindBuiltinProgram(GPU_SHADER_2D_IMAGE);
- const int sizex = triple->x;
- const int sizey = triple->y;
-
- /* wmOrtho for the screen has this same offset */
- ratiox = sizex;
- ratioy = sizey;
- halfx = GLA_PIXEL_OFS;
- halfy = GLA_PIXEL_OFS;
-
- /* texture rectangle has unnormalized coordinates */
- if (triple->target == GL_TEXTURE_2D) {
- ratiox /= triple->x;
- ratioy /= triple->y;
- halfx /= triple->x;
- halfy /= triple->y;
- }
+ int soffx = WM_window_pixels_x(win) * 0.5f;
+ if (view == STEREO_LEFT_ID) {
+ if (!cross_eyed)
+ soffx = 0;
+ }
+ else { //RIGHT_LEFT_ID
+ if (cross_eyed)
+ soffx = 0;
+ }
- glEnable(triple->target);
- glBindTexture(triple->target, triple->bind);
+ const int sizex = WM_window_pixels_x(win);
+ const int sizey = WM_window_pixels_y(win);
- glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
- glBegin(GL_QUADS);
- glTexCoord2f(halfx, halfy);
- glVertex2f(soffx, 0);
+ /* wmOrtho for the screen has this same offset */
+ const float halfx = GLA_PIXEL_OFS / sizex;
+ const float halfy = GLA_PIXEL_OFS / sizex;
- glTexCoord2f(ratiox + halfx, halfy);
- glVertex2f(soffx + (sizex * 0.5f), 0);
+ immUniform1i("image", 0); /* texture is already bound to GL_TEXTURE0 unit */
- glTexCoord2f(ratiox + halfx, ratioy + halfy);
- glVertex2f(soffx + (sizex * 0.5f), sizey);
+ immBegin(GWN_PRIM_TRI_FAN, 4);
- glTexCoord2f(halfx, ratioy + halfy);
- glVertex2f(soffx, sizey);
- glEnd();
+ immAttrib2f(texcoord, halfx, halfy);
+ immVertex2f(pos, soffx, 0.0f);
- glBindTexture(triple->target, 0);
- glDisable(triple->target);
- }
+ immAttrib2f(texcoord, 1.0f + halfx, halfy);
+ immVertex2f(pos, soffx + (sizex * 0.5f), 0.0f);
+
+ immAttrib2f(texcoord, 1.0f + halfx, 1.0f + halfy);
+ immVertex2f(pos, soffx + (sizex * 0.5f), sizey);
+
+ immAttrib2f(texcoord, halfx, 1.0f + halfy);
+ immVertex2f(pos, soffx, sizey);
+
+ immEnd();
+
+ immUnbindProgram();
}
-static void wm_method_draw_stereo3d_topbottom(wmWindow *win)
+void wm_stereo3d_draw_topbottom(wmWindow *win, int view)
{
- wmDrawData *drawdata;
- wmDrawTriple *triple;
- float halfx, halfy, ratiox, ratioy;
- int view;
+ Gwn_VertFormat *format = immVertexFormat();
+ uint texcoord = GWN_vertformat_attr_add(format, "texCoord", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+ uint pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT);
+
+ immBindBuiltinProgram(GPU_SHADER_2D_IMAGE);
+
int soffy;
+ if (view == STEREO_LEFT_ID) {
+ soffy = WM_window_pixels_y(win) * 0.5f;
+ }
+ else { /* STEREO_RIGHT_ID */
+ soffy = 0;
+ }
- for (view = 0; view < 2; view ++) {
- drawdata = BLI_findlink(&win->drawdata, (view * 2) + 1);
- triple = drawdata->triple;
+ const int sizex = WM_window_pixels_x(win);
+ const int sizey = WM_window_pixels_y(win);
- if (view == STEREO_LEFT_ID) {
- soffy = WM_window_pixels_y(win) * 0.5f;
- }
- else { /* STEREO_RIGHT_ID */
- soffy = 0;
- }
+ /* wmOrtho for the screen has this same offset */
+ const float halfx = GLA_PIXEL_OFS / sizex;
+ const float halfy = GLA_PIXEL_OFS / sizex;
- const int sizex = triple->x;
- const int sizey = triple->y;
-
- /* wmOrtho for the screen has this same offset */
- ratiox = sizex;
- ratioy = sizey;
- halfx = GLA_PIXEL_OFS;
- halfy = GLA_PIXEL_OFS;
-
- /* texture rectangle has unnormalized coordinates */
- if (triple->target == GL_TEXTURE_2D) {
- ratiox /= triple->x;
- ratioy /= triple->y;
- halfx /= triple->x;
- halfy /= triple->y;
- }
+ immUniform1i("image", 0); /* texture is already bound to GL_TEXTURE0 unit */
- glEnable(triple->target);
- glBindTexture(triple->target, triple->bind);
+ immBegin(GWN_PRIM_TRI_FAN, 4);
- glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
- glBegin(GL_QUADS);
- glTexCoord2f(halfx, halfy);
- glVertex2f(0, soffy);
+ immAttrib2f(texcoord, halfx, halfy);
+ immVertex2f(pos, 0.0f, soffy);
- glTexCoord2f(ratiox + halfx, halfy);
- glVertex2f(sizex, soffy);
+ immAttrib2f(texcoord, 1.0f + halfx, halfy);
+ immVertex2f(pos, sizex, soffy);
- glTexCoord2f(ratiox + halfx, ratioy + halfy);
- glVertex2f(sizex, soffy + (sizey * 0.5f));
+ immAttrib2f(texcoord, 1.0f + halfx, 1.0f + halfy);
+ immVertex2f(pos, sizex, soffy + (sizey * 0.5f));
- glTexCoord2f(halfx, ratioy + halfy);
- glVertex2f(0, soffy + (sizey * 0.5f));
- glEnd();
+ immAttrib2f(texcoord, halfx, 1.0f + halfy);
+ immVertex2f(pos, 0.0f, soffy + (sizey * 0.5f));
- glBindTexture(triple->target, 0);
- glDisable(triple->target);
- }
-}
+ immEnd();
-void wm_method_draw_stereo3d(const bContext *UNUSED(C), wmWindow *win)
-{
- switch (win->stereo3d_format->display_mode) {
- case S3D_DISPLAY_ANAGLYPH:
- wm_method_draw_stereo3d_anaglyph(win);
- break;
- case S3D_DISPLAY_INTERLACE:
- wm_method_draw_stereo3d_interlace(win);
- break;
- case S3D_DISPLAY_PAGEFLIP:
- wm_method_draw_stereo3d_pageflip(win);
- break;
- case S3D_DISPLAY_SIDEBYSIDE:
- wm_method_draw_stereo3d_sidebyside(win);
- break;
- case S3D_DISPLAY_TOPBOTTOM:
- wm_method_draw_stereo3d_topbottom(win);
- break;
- default:
- break;
- }
+ immUnbindProgram();
}
+
static bool wm_stereo3d_quadbuffer_supported(void)
{
- int gl_stereo = 0;
- glGetBooleanv(GL_STEREO, (GLboolean *)&gl_stereo);
- return gl_stereo != 0;
+ GLboolean stereo = GL_FALSE;
+ glGetBooleanv(GL_STEREO, &stereo);
+ return stereo == GL_TRUE;
}
static bool wm_stereo3d_is_fullscreen_required(eStereoDisplayMode stereo_display)
@@ -324,7 +268,8 @@ static bool wm_stereo3d_is_fullscreen_required(eStereoDisplayMode stereo_display
bool WM_stereo3d_enabled(wmWindow *win, bool skip_stereo3d_check)
{
- bScreen *screen = win->screen;
+ const bScreen *screen = WM_window_get_active_screen(win);
+ const Scene *scene = WM_window_get_active_scene(win);
/* some 3d methods change the window arrangement, thus they shouldn't
* toggle on/off just because there is no 3d elements being drawn */
@@ -332,7 +277,7 @@ bool WM_stereo3d_enabled(wmWindow *win, bool skip_stereo3d_check)
return GHOST_GetWindowState(win->ghostwin) == GHOST_kWindowStateFullScreen;
}
- if ((skip_stereo3d_check == false) && (ED_screen_stereo3d_required(screen) == false)) {
+ if ((skip_stereo3d_check == false) && (ED_screen_stereo3d_required(screen, scene) == false)) {
return false;
}
@@ -459,7 +404,7 @@ int wm_stereo3d_set_exec(bContext *C, wmOperator *op)
prev_display_mode != win_src->stereo3d_format->display_mode)
{
/* in case the hardward supports pageflip but not the display */
- if ((win_dst = wm_window_copy_test(C, win_src))) {
+ if ((win_dst = wm_window_copy_test(C, win_src, false, false))) {
/* pass */
}
else {
@@ -469,14 +414,16 @@ int wm_stereo3d_set_exec(bContext *C, wmOperator *op)
}
}
else if (win_src->stereo3d_format->display_mode == S3D_DISPLAY_PAGEFLIP) {
- /* ED_screen_duplicate() can't handle other cases yet T44688 */
- if (win_src->screen->state != SCREENNORMAL) {
+ const bScreen *screen = WM_window_get_active_screen(win_src);
+
+ /* ED_workspace_layout_duplicate() can't handle other cases yet T44688 */
+ if (screen->state != SCREENNORMAL) {
BKE_report(op->reports, RPT_ERROR,
"Failed to switch to Time Sequential mode when in fullscreen");
ok = false;
}
/* pageflip requires a new window to be created with the proper OS flags */
- else if ((win_dst = wm_window_copy_test(C, win_src))) {
+ else if ((win_dst = wm_window_copy_test(C, win_src, false, false))) {
if (wm_stereo3d_quadbuffer_supported()) {
BKE_report(op->reports, RPT_INFO, "Quad-buffer window successfully created");
}
diff --git a/source/blender/windowmanager/intern/wm_subwindow.c b/source/blender/windowmanager/intern/wm_subwindow.c
index 214e8bd84ce..f55eee69f71 100644
--- a/source/blender/windowmanager/intern/wm_subwindow.c
+++ b/source/blender/windowmanager/intern/wm_subwindow.c
@@ -21,334 +21,87 @@
* Contributor(s): 2007 Blender Foundation (refactor)
*
* ***** END GPL LICENSE BLOCK *****
- *
- *
- * Subwindow opengl handling.
- * BTW: subwindows open/close in X11 are way too slow, tried it, and choose for my own system... (ton)
- *
*/
/** \file blender/windowmanager/intern/wm_subwindow.c
* \ingroup wm
*
- * Internal subwindows used for OpenGL state, used for regions and screens.
+ * OpenGL utilities for setting up 2D viewport for window and regions.
*/
-#include <string.h>
-
-#include "MEM_guardedalloc.h"
+#include "BLI_math.h"
+#include "BLI_rect.h"
-#include "DNA_windowmanager_types.h"
#include "DNA_screen_types.h"
-
-#include "BLI_blenlib.h"
-#include "BLI_math.h"
-#include "BLI_utildefines.h"
+#include "DNA_windowmanager_types.h"
#include "BIF_gl.h"
-#include "GPU_extensions.h"
-#include "GPU_basic_shader.h"
+#include "GPU_matrix.h"
#include "WM_api.h"
-#include "wm_subwindow.h"
-
-/**
- * \note #wmSubWindow stored in #wmWindow but not exposed outside this C file,
- * it seems a bit redundant (area regions can store it too, but we keep it
- * because we can store all kind of future opengl fanciness here.
- *
- * We use indices and array because:
- * - index has safety, no pointers from this C file hanging around
- * - fast lookups of indices with array, list would give overhead
- * - old code used it this way...
- * - keep option open to have 2 screens using same window
- */
-
-typedef struct wmSubWindow {
- struct wmSubWindow *next, *prev;
-
- rcti winrct;
- int swinid;
-} wmSubWindow;
-
-
-/* ******************* open, free, set, get data ******************** */
-
-/* not subwindow itself */
-static void wm_subwindow_free(wmSubWindow *UNUSED(swin))
-{
- /* future fancy stuff */
-}
-
-void wm_subwindows_free(wmWindow *win)
-{
- wmSubWindow *swin;
-
- for (swin = win->subwindows.first; swin; swin = swin->next)
- wm_subwindow_free(swin);
-
- BLI_freelistN(&win->subwindows);
-}
-
-
-int wm_subwindow_get_id(wmWindow *win)
-{
- if (win->curswin)
- return win->curswin->swinid;
- return 0;
-}
-
-static wmSubWindow *swin_from_swinid(wmWindow *win, int swinid)
-{
- wmSubWindow *swin;
-
- for (swin = win->subwindows.first; swin; swin = swin->next)
- if (swin->swinid == swinid)
- break;
- return swin;
-}
-
-
-static void wm_swin_size_get(wmSubWindow *swin, int *x, int *y)
-{
- *x = BLI_rcti_size_x(&swin->winrct) + 1;
- *y = BLI_rcti_size_y(&swin->winrct) + 1;
-}
-void wm_subwindow_size_get(wmWindow *win, int swinid, int *x, int *y)
-{
- wmSubWindow *swin = swin_from_swinid(win, swinid);
-
- if (swin) {
- wm_swin_size_get(swin, x, y);
- }
-}
-
-
-static void wm_swin_origin_get(wmSubWindow *swin, int *x, int *y)
-{
- *x = swin->winrct.xmin;
- *y = swin->winrct.ymin;
-}
-void wm_subwindow_origin_get(wmWindow *win, int swinid, int *x, int *y)
-{
- wmSubWindow *swin = swin_from_swinid(win, swinid);
-
- if (swin) {
- wm_swin_origin_get(swin, x, y);
- }
-}
-
-
-static void wm_swin_matrix_get(wmWindow *win, wmSubWindow *swin, float mat[4][4])
-{
- /* used by UI, should find a better way to get the matrix there */
- if (swin->swinid == win->screen->mainwin) {
- int width, height;
-
- wm_swin_size_get(swin, &width, &height);
- orthographic_m4(mat, -GLA_PIXEL_OFS, (float)width - GLA_PIXEL_OFS, -GLA_PIXEL_OFS, (float)height - GLA_PIXEL_OFS, -100, 100);
- }
- else {
- glGetFloatv(GL_PROJECTION_MATRIX, (float *)mat);
- }
-}
-void wm_subwindow_matrix_get(wmWindow *win, int swinid, float mat[4][4])
-{
- wmSubWindow *swin = swin_from_swinid(win, swinid);
- if (swin) {
- wm_swin_matrix_get(win, swin, mat);
- }
-}
-
-
-static void wm_swin_rect_get(wmSubWindow *swin, rcti *r_rect)
+void wmViewport(const rcti *winrct)
{
- *r_rect = swin->winrct;
-}
-void wm_subwindow_rect_get(wmWindow *win, int swinid, rcti *r_rect)
-{
- wmSubWindow *swin = swin_from_swinid(win, swinid);
+ int width = BLI_rcti_size_x(winrct) + 1;
+ int height = BLI_rcti_size_y(winrct) + 1;
- if (swin) {
- wm_swin_rect_get(swin, r_rect);
- }
-}
-
-
-static void wm_swin_rect_set(wmSubWindow *swin, const rcti *rect)
-{
- swin->winrct = *rect;
-}
-void wm_subwindow_rect_set(wmWindow *win, int swinid, const rcti *rect)
-{
- wmSubWindow *swin = swin_from_swinid(win, swinid);
-
- if (swin) {
- wm_swin_rect_set(swin, rect);
- }
-}
-
-
-/* always sets pixel-precise 2D window/view matrices */
-/* coords is in whole pixels. xmin = 15, xmax = 16: means window is 2 pix big */
-int wm_subwindow_open(wmWindow *win, const rcti *winrct, bool activate)
-{
- wmSubWindow *swin;
- int width, height;
- int freewinid = 1;
-
- for (swin = win->subwindows.first; swin; swin = swin->next)
- if (freewinid <= swin->swinid)
- freewinid = swin->swinid + 1;
-
- win->curswin = swin = MEM_callocN(sizeof(wmSubWindow), "swinopen");
- BLI_addtail(&win->subwindows, swin);
-
- swin->swinid = freewinid;
- swin->winrct = *winrct;
-
- if (activate) {
- /* and we appy it all right away */
- wmSubWindowSet(win, swin->swinid);
-
- /* extra service */
- wm_swin_size_get(swin, &width, &height);
- wmOrtho2_pixelspace(width, height);
- glLoadIdentity();
- }
-
- return swin->swinid;
-}
-
-void wm_subwindow_close(wmWindow *win, int swinid)
-{
- wmSubWindow *swin = swin_from_swinid(win, swinid);
+ glViewport(winrct->xmin, winrct->ymin, width, height);
+ glScissor(winrct->xmin, winrct->ymin, width, height);
- if (swin) {
- if (swin == win->curswin)
- win->curswin = NULL;
- wm_subwindow_free(swin);
- BLI_remlink(&win->subwindows, swin);
- MEM_freeN(swin);
- }
- else {
- printf("%s: Internal error, bad winid: %d\n", __func__, swinid);
- }
+ wmOrtho2_pixelspace(width, height);
+ gpuLoadIdentity();
}
-/* pixels go from 0-99 for a 100 pixel window */
-void wm_subwindow_position(wmWindow *win, int swinid, const rcti *winrct, bool activate)
+void wmPartialViewport(rcti *drawrct, const rcti *winrct, const rcti *partialrct)
{
- wmSubWindow *swin = swin_from_swinid(win, swinid);
-
- if (swin) {
- const int winsize_x = WM_window_pixels_x(win);
- const int winsize_y = WM_window_pixels_y(win);
-
- int width, height;
-
- swin->winrct = *winrct;
+ /* Setup part of the viewport for partial redraw. */
+ bool scissor_pad;
- /* CRITICAL, this clamping ensures that
- * the viewport never goes outside the screen
- * edges (assuming the x, y coords aren't
- * outside). This caused a hardware lock
- * on Matrox cards if it happens.
- *
- * Really Blender should never _ever_ try
- * to do such a thing, but just to be safe
- * clamp it anyway (or fix the bScreen
- * scaling routine, and be damn sure you
- * fixed it). - zr (2001!)
- */
-
- if (swin->winrct.xmax > winsize_x)
- swin->winrct.xmax = winsize_x;
- if (swin->winrct.ymax > winsize_y)
- swin->winrct.ymax = winsize_y;
-
- if (activate) {
- /* extra service */
- wmSubWindowSet(win, swinid);
- wm_swin_size_get(swin, &width, &height);
- wmOrtho2_pixelspace(width, height);
- }
+ if (partialrct->xmin == partialrct->xmax) {
+ /* Full region. */
+ *drawrct = *winrct;
+ scissor_pad = true;
}
else {
- printf("%s: Internal error, bad winid: %d\n", __func__, swinid);
+ /* Partial redraw, clipped to region. */
+ BLI_rcti_isect(winrct, partialrct, drawrct);
+ scissor_pad = false;
}
-}
-/* ---------------- WM versions of OpenGL style API calls ------------------------ */
-/* ----------------- exported in WM_api.h ------------------------------------------------------ */
+ int x = drawrct->xmin - winrct->xmin;
+ int y = drawrct->ymin - winrct->ymin;
+ int width = BLI_rcti_size_x(winrct) + 1;
+ int height = BLI_rcti_size_y(winrct) + 1;
-/* internal state, no threaded opengl! XXX */
-static wmWindow *_curwindow = NULL;
-static wmSubWindow *_curswin = NULL;
+ int scissor_width = BLI_rcti_size_x(drawrct);
+ int scissor_height = BLI_rcti_size_y(drawrct);
-void wmSubWindowScissorSet(wmWindow *win, int swinid, const rcti *srct, bool srct_pad)
-{
- int width, height;
- _curswin = swin_from_swinid(win, swinid);
-
- if (_curswin == NULL) {
- printf("%s %d: doesn't exist\n", __func__, swinid);
- return;
+ /* Partial redraw rect uses different convention than region rect,
+ * so compensate for that here. One pixel offset is noticeable with
+ * viewport border render. */
+ if (scissor_pad) {
+ scissor_width += 1;
+ scissor_height += 1;
}
- win->curswin = _curswin;
- _curwindow = win;
-
- width = BLI_rcti_size_x(&_curswin->winrct) + 1;
- height = BLI_rcti_size_y(&_curswin->winrct) + 1;
- glViewport(_curswin->winrct.xmin, _curswin->winrct.ymin, width, height);
-
- if (srct) {
- int scissor_width = BLI_rcti_size_x(srct);
- int scissor_height = BLI_rcti_size_y(srct);
-
- /* typically a single pixel doesn't matter,
- * but one pixel offset is noticeable with viewport border render */
- if (srct_pad) {
- scissor_width += 1;
- scissor_height += 1;
- }
-
- glScissor(srct->xmin, srct->ymin, scissor_width, scissor_height);
- }
- else
- glScissor(_curswin->winrct.xmin, _curswin->winrct.ymin, width, height);
+ glViewport(0, 0, width, height);
+ glScissor(x, y, scissor_width, scissor_height);
wmOrtho2_pixelspace(width, height);
- glLoadIdentity();
-
- glFlush();
-}
-
-/* enable the WM versions of opengl calls */
-void wmSubWindowSet(wmWindow *win, int swinid)
-{
- wmSubWindowScissorSet(win, swinid, NULL, true);
+ gpuLoadIdentity();
}
-void wmFrustum(float x1, float x2, float y1, float y2, float n, float f)
+void wmWindowViewport(wmWindow *win)
{
- glMatrixMode(GL_PROJECTION);
- glLoadIdentity();
- glFrustum(x1, x2, y1, y2, n, f);
- glMatrixMode(GL_MODELVIEW);
-}
-
-void wmOrtho(float x1, float x2, float y1, float y2, float n, float f)
-{
- glMatrixMode(GL_PROJECTION);
- glLoadIdentity();
+ int width = WM_window_pixels_x(win);
+ int height = WM_window_pixels_y(win);
- glOrtho(x1, x2, y1, y2, n, f);
+ glViewport(0, 0, width, height);
+ glScissor(0, 0, width, height);
- glMatrixMode(GL_MODELVIEW);
+ wmOrtho2_pixelspace(width, height);
+ gpuLoadIdentity();
}
void wmOrtho2(float x1, float x2, float y1, float y2)
@@ -357,7 +110,7 @@ void wmOrtho2(float x1, float x2, float y1, float y2)
if (x1 == x2) x2 += 1.0f;
if (y1 == y2) y2 += 1.0f;
- wmOrtho(x1, x2, y1, y2, -100, 100);
+ gpuOrtho(x1, x2, y1, y2, -100, 100);
}
static void wmOrtho2_offset(const float x, const float y, const float ofs)
@@ -365,9 +118,7 @@ static void wmOrtho2_offset(const float x, const float y, const float ofs)
wmOrtho2(ofs, x + ofs, ofs, y + ofs);
}
-/**
- * default pixel alignment.
- */
+/* Default pixel alignment for regions. */
void wmOrtho2_region_pixelspace(const ARegion *ar)
{
wmOrtho2_offset(ar->winx, ar->winy, -0.01f);
@@ -378,4 +129,9 @@ void wmOrtho2_pixelspace(const float x, const float y)
wmOrtho2_offset(x, y, -GLA_PIXEL_OFS);
}
-/* ********** END MY WINDOW ************** */
+void wmGetProjectionMatrix(float mat[4][4], const rcti *winrct)
+{
+ int width = BLI_rcti_size_x(winrct) + 1;
+ int height = BLI_rcti_size_y(winrct) + 1;
+ orthographic_m4(mat, -GLA_PIXEL_OFS, (float)width - GLA_PIXEL_OFS, -GLA_PIXEL_OFS, (float)height - GLA_PIXEL_OFS, -100, 100);
+}
diff --git a/source/blender/windowmanager/intern/wm_toolsystem.c b/source/blender/windowmanager/intern/wm_toolsystem.c
new file mode 100644
index 00000000000..d06cc21ec21
--- /dev/null
+++ b/source/blender/windowmanager/intern/wm_toolsystem.c
@@ -0,0 +1,602 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/windowmanager/intern/wm_toolsystem.c
+ * \ingroup wm
+ *
+ * Experimental tool-system>
+ */
+
+#include <string.h>
+
+#include "CLG_log.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_utildefines.h"
+#include "BLI_string.h"
+#include "BLI_listbase.h"
+
+#include "DNA_ID.h"
+#include "DNA_scene_types.h"
+#include "DNA_space_types.h"
+#include "DNA_windowmanager_types.h"
+#include "DNA_workspace_types.h"
+#include "DNA_object_types.h"
+
+#include "BKE_context.h"
+#include "BKE_library.h"
+#include "BKE_main.h"
+#include "BKE_paint.h"
+#include "BKE_idprop.h"
+#include "BKE_workspace.h"
+
+#include "RNA_access.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+#include "WM_message.h"
+#include "WM_toolsystem.h" /* own include */
+
+static void toolsystem_reinit_with_toolref(
+ bContext *C, WorkSpace *UNUSED(workspace), bToolRef *tref);
+static void toolsystem_reinit_ensure_toolref(
+ bContext *C, WorkSpace *workspace, const bToolKey *tkey, const char *default_tool);
+static void toolsystem_refresh_screen_from_active_tool(
+ Main *bmain, WorkSpace *workspace, bToolRef *tref);
+
+/* -------------------------------------------------------------------- */
+/** \name Tool Reference API
+ * \{ */
+
+struct bToolRef *WM_toolsystem_ref_from_context(struct bContext *C)
+{
+ WorkSpace *workspace = CTX_wm_workspace(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ ScrArea *sa = CTX_wm_area(C);
+ const bToolKey tkey = {
+ .space_type = sa->spacetype,
+ .mode = WM_toolsystem_mode_from_spacetype(view_layer, sa, sa->spacetype),
+ };
+ bToolRef *tref = WM_toolsystem_ref_find(workspace, &tkey);
+ /* We could return 'sa->runtime.tool' in this case. */
+ if (sa->runtime.is_tool_set) {
+ BLI_assert(tref == sa->runtime.tool);
+ }
+ return tref;
+}
+
+struct bToolRef_Runtime *WM_toolsystem_runtime_from_context(struct bContext *C)
+{
+ bToolRef *tref = WM_toolsystem_ref_from_context(C);
+ return tref ? tref->runtime : NULL;
+}
+
+bToolRef *WM_toolsystem_ref_find(WorkSpace *workspace, const bToolKey *tkey)
+{
+ LISTBASE_FOREACH (bToolRef *, tref, &workspace->tools) {
+ if ((tref->space_type == tkey->space_type) &&
+ (tref->mode == tkey->mode))
+ {
+ return tref;
+ }
+ }
+ return NULL;
+}
+
+bToolRef_Runtime *WM_toolsystem_runtime_find(WorkSpace *workspace, const bToolKey *tkey)
+{
+ bToolRef *tref = WM_toolsystem_ref_find(workspace, tkey);
+ return tref ? tref->runtime : NULL;
+}
+
+bool WM_toolsystem_ref_ensure(
+ struct WorkSpace *workspace, const bToolKey *tkey,
+ bToolRef **r_tref)
+{
+ bToolRef *tref = WM_toolsystem_ref_find(workspace, tkey);
+ if (tref) {
+ *r_tref = tref;
+ return false;
+ }
+ tref = MEM_callocN(sizeof(*tref), __func__);
+ BLI_addhead(&workspace->tools, tref);
+ tref->space_type = tkey->space_type;
+ tref->mode = tkey->mode;
+ *r_tref = tref;
+ return true;
+}
+
+/** \} */
+
+
+static void toolsystem_unlink_ref(bContext *C, WorkSpace *workspace, bToolRef *tref)
+{
+ bToolRef_Runtime *tref_rt = tref->runtime;
+
+ if (tref_rt->manipulator_group[0]) {
+ wmManipulatorGroupType *wgt = WM_manipulatorgrouptype_find(tref_rt->manipulator_group, false);
+ if (wgt != NULL) {
+ bool found = false;
+
+ /* TODO(campbell) */
+ Main *bmain = CTX_data_main(C);
+#if 0
+ wmWindowManager *wm = bmain->wm.first;
+ /* Check another workspace isn't using this tool. */
+ for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ const WorkSpace *workspace_iter = WM_window_get_active_workspace(win);
+ if (workspace != workspace_iter) {
+ if (STREQ(workspace->tool.manipulator_group, workspace_iter->tool.manipulator_group)) {
+ found = true;
+ break;
+ }
+ }
+ }
+#else
+ UNUSED_VARS(workspace);
+#endif
+ if (!found) {
+ wmManipulatorMapType *mmap_type = WM_manipulatormaptype_ensure(&wgt->mmap_params);
+ WM_manipulatormaptype_group_unlink(C, bmain, mmap_type, wgt);
+ }
+ }
+ }
+}
+void WM_toolsystem_unlink(bContext *C, WorkSpace *workspace, const bToolKey *tkey)
+{
+ bToolRef *tref = WM_toolsystem_ref_find(workspace, tkey);
+ if (tref && tref->runtime) {
+ toolsystem_unlink_ref(C, workspace, tref);
+ }
+}
+
+static void toolsystem_ref_link(bContext *C, WorkSpace *workspace, bToolRef *tref)
+{
+ bToolRef_Runtime *tref_rt = tref->runtime;
+ if (tref_rt->manipulator_group[0]) {
+ const char *idname = tref_rt->manipulator_group;
+ wmManipulatorGroupType *wgt = WM_manipulatorgrouptype_find(idname, false);
+ if (wgt != NULL) {
+ WM_manipulator_group_type_ensure_ptr(wgt);
+ }
+ else {
+ CLOG_WARN(WM_LOG_TOOLS, "'%s' widget not found", idname);
+ }
+ }
+
+ if (tref_rt->data_block[0]) {
+ Main *bmain = CTX_data_main(C);
+
+ /* Currently only brush data-blocks supported. */
+ struct Brush *brush = (struct Brush *)BKE_libblock_find_name(bmain, ID_BR, tref_rt->data_block);
+
+ if (brush) {
+ wmWindowManager *wm = bmain->wm.first;
+ for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ if (workspace == WM_window_get_active_workspace(win)) {
+ Scene *scene = WM_window_get_active_scene(win);
+ ViewLayer *view_layer = WM_window_get_active_view_layer(win);
+ Paint *paint = BKE_paint_get_active(scene, view_layer);
+ if (paint) {
+ if (brush) {
+ BKE_paint_brush_set(paint, brush);
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+static void toolsystem_refresh_ref(bContext *C, WorkSpace *workspace, bToolRef *tref)
+{
+ if (tref->runtime == NULL) {
+ return;
+ }
+ /* currently same operation. */
+ toolsystem_ref_link(C, workspace, tref);
+}
+void WM_toolsystem_refresh(bContext *C, WorkSpace *workspace, const bToolKey *tkey)
+{
+ bToolRef *tref = WM_toolsystem_ref_find(workspace, tkey);
+ if (tref) {
+ toolsystem_refresh_ref(C, workspace, tref);
+ }
+}
+
+static void toolsystem_reinit_ref(bContext *C, WorkSpace *workspace, bToolRef *tref)
+{
+ toolsystem_reinit_with_toolref(C, workspace, tref);
+}
+void WM_toolsystem_reinit(bContext *C, WorkSpace *workspace, const bToolKey *tkey)
+{
+ bToolRef *tref = WM_toolsystem_ref_find(workspace, tkey);
+ if (tref) {
+ toolsystem_reinit_ref(C, workspace, tref);
+ }
+}
+
+/* Operate on all active tools. */
+void WM_toolsystem_unlink_all(struct bContext *C, struct WorkSpace *workspace)
+{
+ LISTBASE_FOREACH (bToolRef *, tref, &workspace->tools) {
+ tref->tag = 0;
+ }
+
+ LISTBASE_FOREACH (bToolRef *, tref, &workspace->tools) {
+ if (tref->runtime) {
+ if (tref->tag == 0) {
+ toolsystem_unlink_ref(C, workspace, tref);
+ tref->tag = 1;
+ }
+ }
+ }
+}
+
+void WM_toolsystem_refresh_all(struct bContext *C, struct WorkSpace *workspace)
+{
+ BLI_assert(0);
+ LISTBASE_FOREACH (bToolRef *, tref, &workspace->tools) {
+ toolsystem_refresh_ref(C, workspace, tref);
+ }
+}
+void WM_toolsystem_reinit_all(struct bContext *C, wmWindow *win)
+{
+ bScreen *screen = WM_window_get_active_screen(win);
+ ViewLayer *view_layer = WM_window_get_active_view_layer(win);
+ for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
+ WorkSpace *workspace = WM_window_get_active_workspace(win);
+ const bToolKey tkey = {
+ .space_type = sa->spacetype,
+ .mode = WM_toolsystem_mode_from_spacetype(view_layer, sa, sa->spacetype),
+ };
+ bToolRef *tref = WM_toolsystem_ref_find(workspace, &tkey);
+ if (tref) {
+ if (tref->tag == 0) {
+ toolsystem_reinit_ref(C, workspace, tref);
+ tref->tag = 1;
+ }
+ }
+ }
+}
+
+void WM_toolsystem_ref_set_from_runtime(
+ struct bContext *C, struct WorkSpace *workspace, bToolRef *tref,
+ const bToolRef_Runtime *tref_rt, const char *idname)
+{
+ Main *bmain = CTX_data_main(C);
+
+ if (tref->runtime) {
+ toolsystem_unlink_ref(C, workspace, tref);
+ }
+
+ STRNCPY(tref->idname, idname);
+
+ /* BAD DESIGN WARNING: used for topbar. */
+ workspace->tools_space_type = tref->space_type;
+ workspace->tools_mode = tref->mode;
+
+ if (tref->runtime == NULL) {
+ tref->runtime = MEM_callocN(sizeof(*tref->runtime), __func__);
+ }
+
+ if (tref_rt != tref->runtime) {
+ *tref->runtime = *tref_rt;
+ }
+
+ toolsystem_ref_link(C, workspace, tref);
+
+ toolsystem_refresh_screen_from_active_tool(bmain, workspace, tref);
+
+ {
+ struct wmMsgBus *mbus = CTX_wm_message_bus(C);
+ WM_msg_publish_rna_prop(
+ mbus, &workspace->id, workspace, WorkSpace, tools);
+ }
+}
+
+void WM_toolsystem_init(bContext *C)
+{
+ Main *bmain = CTX_data_main(C);
+
+ BLI_assert(CTX_wm_window(C) == NULL);
+
+ LISTBASE_FOREACH (WorkSpace *, workspace, &bmain->workspaces) {
+ LISTBASE_FOREACH (bToolRef *, tref, &workspace->tools) {
+ MEM_SAFE_FREE(tref->runtime);
+ tref->tag = 0;
+ }
+ }
+
+ for (wmWindowManager *wm = bmain->wm.first; wm; wm = wm->id.next) {
+ for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ CTX_wm_window_set(C, win);
+ WorkSpace *workspace = WM_window_get_active_workspace(win);
+ bScreen *screen = WM_window_get_active_screen(win);
+ ViewLayer *view_layer = WM_window_get_active_view_layer(win);
+ for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
+ const bToolKey tkey = {
+ .space_type = sa->spacetype,
+ .mode = WM_toolsystem_mode_from_spacetype(view_layer, sa, sa->spacetype),
+ };
+ bToolRef *tref = WM_toolsystem_ref_find(workspace, &tkey);
+ if (tref) {
+ if (tref->tag == 0) {
+ toolsystem_reinit_ref(C, workspace, tref);
+ tref->tag = 1;
+ }
+ }
+ }
+ CTX_wm_window_set(C, NULL);
+ }
+ }
+}
+
+int WM_toolsystem_mode_from_spacetype(
+ ViewLayer *view_layer, ScrArea *sa, int spacetype)
+{
+ int mode = -1;
+ switch (spacetype) {
+ case SPACE_VIEW3D:
+ {
+ /* 'sa' may be NULL in this case. */
+ Object *obact = OBACT(view_layer);
+ if (obact != NULL) {
+ Object *obedit = OBEDIT_FROM_OBACT(obact);
+ mode = CTX_data_mode_enum_ex(obedit, obact, obact->mode);
+ }
+ else {
+ mode = CTX_MODE_OBJECT;
+ }
+ break;
+ }
+ case SPACE_IMAGE:
+ {
+ SpaceImage *sima = sa->spacedata.first;
+ mode = sima->mode;
+ break;
+ }
+ }
+ return mode;
+}
+
+bool WM_toolsystem_key_from_context(
+ ViewLayer *view_layer, ScrArea *sa, bToolKey *tkey)
+{
+ int space_type = SPACE_EMPTY;
+ int mode = -1;
+
+ if (sa != NULL) {
+ space_type = sa->spacetype;
+ mode = WM_toolsystem_mode_from_spacetype(view_layer, sa, space_type);
+ }
+
+ if (mode != -1) {
+ tkey->space_type = space_type;
+ tkey->mode = mode;
+ return true;
+ }
+ return false;
+}
+
+void WM_toolsystem_refresh_screen_area(WorkSpace *workspace, ViewLayer *view_layer, ScrArea *sa)
+{
+ sa->runtime.tool = NULL;
+ sa->runtime.is_tool_set = true;
+ const int mode = WM_toolsystem_mode_from_spacetype(view_layer, sa, sa->spacetype);
+ for (bToolRef *tref = workspace->tools.first; tref; tref = tref->next) {
+ if (tref->space_type == sa->spacetype) {
+ if (tref->mode == mode) {
+ sa->runtime.tool = tref;
+ break;
+ }
+ }
+ }
+}
+
+void WM_toolsystem_refresh_screen_all(Main *bmain)
+{
+ /* Update all ScrArea's tools */
+ for (wmWindowManager *wm = bmain->wm.first; wm; wm = wm->id.next) {
+ for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ WorkSpace *workspace = WM_window_get_active_workspace(win);
+ bool space_type_has_tools[SPACE_TYPE_LAST + 1] = {0};
+ for (bToolRef *tref = workspace->tools.first; tref; tref = tref->next) {
+ space_type_has_tools[tref->space_type] = true;
+ }
+ bScreen *screen = WM_window_get_active_screen(win);
+ ViewLayer *view_layer = WM_window_get_active_view_layer(win);
+ for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
+ sa->runtime.tool = NULL;
+ sa->runtime.is_tool_set = true;
+ if (space_type_has_tools[sa->spacetype]) {
+ WM_toolsystem_refresh_screen_area(workspace, view_layer, sa);
+ }
+ }
+ }
+ }
+}
+
+static void toolsystem_refresh_screen_from_active_tool(
+ Main *bmain, WorkSpace *workspace, bToolRef *tref)
+{
+ /* Update all ScrArea's tools */
+ for (wmWindowManager *wm = bmain->wm.first; wm; wm = wm->id.next) {
+ for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ if (workspace == WM_window_get_active_workspace(win)) {
+ bScreen *screen = WM_window_get_active_screen(win);
+ ViewLayer *view_layer = WM_window_get_active_view_layer(win);
+ for (ScrArea *sa = screen->areabase.first; sa; sa = sa->next) {
+ if (sa->spacetype == tref->space_type) {
+ int mode = WM_toolsystem_mode_from_spacetype(view_layer, sa, sa->spacetype);
+ if (mode == tref->mode) {
+ sa->runtime.tool = tref;
+ sa->runtime.is_tool_set = true;
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+bToolRef *WM_toolsystem_ref_set_by_name(
+ bContext *C, WorkSpace *workspace, const bToolKey *tkey,
+ const char *name, bool cycle)
+{
+ wmOperatorType *ot = WM_operatortype_find("WM_OT_tool_set_by_name", false);
+ /* On startup, Python operatores are not yet loaded. */
+ if (ot == NULL) {
+ return NULL;
+ }
+ PointerRNA op_props;
+ WM_operator_properties_create_ptr(&op_props, ot);
+ RNA_string_set(&op_props, "name", name);
+
+ /* Will get from context if not set. */
+ bToolKey tkey_from_context;
+ if (tkey == NULL) {
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ ScrArea *sa = CTX_wm_area(C);
+ WM_toolsystem_key_from_context(view_layer, sa, &tkey_from_context);
+ tkey = &tkey_from_context;
+ }
+
+ RNA_enum_set(&op_props, "space_type", tkey->space_type);
+ RNA_boolean_set(&op_props, "cycle", cycle);
+
+ WM_operator_name_call_ptr(C, ot, WM_OP_EXEC_DEFAULT, &op_props);
+ WM_operator_properties_free(&op_props);
+
+ bToolRef *tref = WM_toolsystem_ref_find(workspace, tkey);
+
+ if (tref) {
+ Main *bmain = CTX_data_main(C);
+ toolsystem_refresh_screen_from_active_tool(bmain, workspace, tref);
+ }
+
+ return (tref && STREQ(tref->idname, name)) ? tref : NULL;
+}
+
+static void toolsystem_reinit_with_toolref(
+ bContext *C, WorkSpace *workspace, bToolRef *tref)
+{
+ bToolKey tkey = {
+ .space_type = tref->space_type,
+ .mode = tref->mode,
+ };
+ WM_toolsystem_ref_set_by_name(C, workspace, &tkey, tref->idname, false);
+}
+
+/**
+ * Run after changing modes.
+ */
+static void toolsystem_reinit_ensure_toolref(
+ bContext *C, WorkSpace *workspace, const bToolKey *tkey, const char *default_tool)
+{
+ bToolRef *tref;
+ if (WM_toolsystem_ref_ensure(workspace, tkey, &tref)) {
+ STRNCPY(tref->idname, default_tool);
+ }
+
+ toolsystem_reinit_with_toolref(C, workspace, tref);
+}
+
+void WM_toolsystem_update_from_context_view3d(bContext *C)
+{
+ WorkSpace *workspace = CTX_wm_workspace(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ int space_type = SPACE_VIEW3D;
+ const bToolKey tkey = {
+ .space_type = space_type,
+ .mode = WM_toolsystem_mode_from_spacetype(view_layer, NULL, space_type),
+ };
+ toolsystem_reinit_ensure_toolref(C, workspace, &tkey, "Cursor");
+}
+
+/**
+ * For paint modes to support non-brush tools.
+ */
+bool WM_toolsystem_active_tool_is_brush(const bContext *C)
+{
+ bToolRef_Runtime *tref_rt = WM_toolsystem_runtime_from_context((bContext *)C);
+ return tref_rt && (tref_rt->data_block[0] != '\0');
+}
+
+/* Follow wmMsgNotifyFn spec */
+void WM_toolsystem_do_msg_notify_tag_refresh(
+ bContext *C, wmMsgSubscribeKey *UNUSED(msg_key), wmMsgSubscribeValue *msg_val)
+{
+ WorkSpace *workspace = CTX_wm_workspace(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ ScrArea *sa = msg_val->user_data;
+ int space_type = sa->spacetype;
+ const bToolKey tkey = {
+ .space_type = space_type,
+ .mode = WM_toolsystem_mode_from_spacetype(view_layer, sa, sa->spacetype),
+ };
+ WM_toolsystem_refresh(C, workspace, &tkey);
+}
+
+IDProperty *WM_toolsystem_ref_properties_ensure_idprops(bToolRef *tref)
+{
+ if (tref->properties == NULL) {
+ IDPropertyTemplate val = {0};
+ tref->properties = IDP_New(IDP_GROUP, &val, "wmOperatorProperties");
+ }
+ return tref->properties;
+}
+
+void WM_toolsystem_ref_properties_ensure(bToolRef *tref, wmOperatorType *ot, PointerRNA *ptr)
+{
+ IDProperty *group = WM_toolsystem_ref_properties_ensure_idprops(tref);
+ IDProperty *prop = IDP_GetPropertyFromGroup(group, ot->idname);
+ if (prop == NULL) {
+ IDPropertyTemplate val = {0};
+ prop = IDP_New(IDP_GROUP, &val, "wmOperatorProperties");
+ STRNCPY(prop->name, ot->idname);
+ IDP_ReplaceInGroup_ex(group, prop, NULL);
+ }
+ else {
+ BLI_assert(prop->type == IDP_GROUP);
+ }
+
+ RNA_pointer_create(NULL, ot->srna, prop, ptr);
+}
+
+void WM_toolsystem_ref_properties_init_for_keymap(
+ bToolRef *tref, PointerRNA *dst_ptr, PointerRNA *src_ptr, wmOperatorType *ot)
+{
+ *dst_ptr = *src_ptr;
+ if (dst_ptr->data) {
+ dst_ptr->data = IDP_CopyProperty(dst_ptr->data);
+ }
+ else {
+ IDPropertyTemplate val = {0};
+ dst_ptr->data = IDP_New(IDP_GROUP, &val, "wmOpItemProp");
+ }
+ if (tref->properties != NULL) {
+ IDProperty *prop = IDP_GetPropertyFromGroup(tref->properties, ot->idname);
+ if (prop) {
+ IDP_MergeGroup(dst_ptr->data, prop, true);
+ }
+ }
+}
diff --git a/source/blender/windowmanager/intern/wm_tooltip.c b/source/blender/windowmanager/intern/wm_tooltip.c
index 0d02b4fc4e3..94a44a97afd 100644
--- a/source/blender/windowmanager/intern/wm_tooltip.c
+++ b/source/blender/windowmanager/intern/wm_tooltip.c
@@ -41,7 +41,9 @@ void WM_tooltip_timer_init(
bContext *C, wmWindow *win, ARegion *ar,
wmTooltipInitFn init)
{
- bScreen *screen = win->screen;
+ WM_tooltip_timer_clear(C, win);
+
+ bScreen *screen = WM_window_get_active_screen(win);
wmWindowManager *wm = CTX_wm_manager(C);
if (screen->tool_tip == NULL) {
screen->tool_tip = MEM_callocN(sizeof(*screen->tool_tip), __func__);
@@ -54,7 +56,7 @@ void WM_tooltip_timer_init(
void WM_tooltip_timer_clear(bContext *C, wmWindow *win)
{
wmWindowManager *wm = CTX_wm_manager(C);
- bScreen *screen = win->screen;
+ bScreen *screen = WM_window_get_active_screen(win);
if (screen->tool_tip != NULL) {
if (screen->tool_tip->timer != NULL) {
WM_event_remove_timer(wm, win, screen->tool_tip->timer);
@@ -66,7 +68,7 @@ void WM_tooltip_timer_clear(bContext *C, wmWindow *win)
void WM_tooltip_clear(bContext *C, wmWindow *win)
{
WM_tooltip_timer_clear(C, win);
- bScreen *screen = win->screen;
+ bScreen *screen = WM_window_get_active_screen(win);
if (screen->tool_tip != NULL) {
if (screen->tool_tip->region) {
UI_tooltip_free(C, screen, screen->tool_tip->region);
@@ -80,7 +82,7 @@ void WM_tooltip_clear(bContext *C, wmWindow *win)
void WM_tooltip_init(bContext *C, wmWindow *win)
{
WM_tooltip_timer_clear(C, win);
- bScreen *screen = win->screen;
+ bScreen *screen = WM_window_get_active_screen(win);
if (screen->tool_tip->region) {
UI_tooltip_free(C, screen, screen->tool_tip->region);
screen->tool_tip->region = NULL;
@@ -95,7 +97,7 @@ void WM_tooltip_init(bContext *C, wmWindow *win)
void WM_tooltip_refresh(bContext *C, wmWindow *win)
{
WM_tooltip_timer_clear(C, win);
- bScreen *screen = win->screen;
+ bScreen *screen = WM_window_get_active_screen(win);
if (screen->tool_tip != NULL) {
if (screen->tool_tip->region) {
UI_tooltip_free(C, screen, screen->tool_tip->region);
diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c
index f6ebdae8414..fcd74f32bde 100644
--- a/source/blender/windowmanager/intern/wm_window.c
+++ b/source/blender/windowmanager/intern/wm_window.c
@@ -38,6 +38,7 @@
#include "DNA_listBase.h"
#include "DNA_screen_types.h"
#include "DNA_windowmanager_types.h"
+#include "DNA_workspace_types.h"
#include "MEM_guardedalloc.h"
@@ -51,35 +52,49 @@
#include "BKE_blender.h"
#include "BKE_context.h"
+#include "BKE_icons.h"
+#include "BKE_layer.h"
#include "BKE_library.h"
#include "BKE_global.h"
#include "BKE_main.h"
-
+#include "BKE_screen.h"
+#include "BKE_workspace.h"
#include "RNA_access.h"
+#include "RNA_define.h"
+#include "RNA_enum_types.h"
#include "WM_api.h"
#include "WM_types.h"
#include "wm.h"
#include "wm_draw.h"
#include "wm_window.h"
-#include "wm_subwindow.h"
#include "wm_event_system.h"
+#include "ED_anim_api.h"
+#include "ED_scene.h"
#include "ED_screen.h"
#include "ED_fileselect.h"
#include "UI_interface.h"
-#include "UI_resources.h"
+#include "UI_interface_icons.h"
#include "PIL_time.h"
+#include "GPU_batch.h"
#include "GPU_draw.h"
#include "GPU_extensions.h"
+#include "GPU_framebuffer.h"
#include "GPU_init_exit.h"
-#include "GPU_glew.h"
+#include "GPU_immediate.h"
+#include "GPU_material.h"
+#include "GPU_texture.h"
#include "BLF_api.h"
+#include "UI_resources.h"
+
+#include "../../../intern/gawain/gawain/gwn_context.h"
+
/* for assert */
#ifndef NDEBUG
# include "BLI_threads.h"
@@ -107,6 +122,9 @@ static struct WMInitStruct {
/* ******** win open & close ************ */
+static void wm_window_set_drawable(wmWindowManager *wm, wmWindow *win, bool activate);
+static void wm_window_clear_drawable(wmWindowManager *wm);
+
/* XXX this one should correctly check for apple top header...
* done for Cocoa : returns window contents (and not frame) max size*/
void wm_get_screensize(int *r_width, int *r_height)
@@ -161,13 +179,30 @@ static void wm_window_check_position(rcti *rect)
if (rect->ymin < 0) rect->ymin = 0;
}
-
-static void wm_ghostwindow_destroy(wmWindow *win)
+static void wm_ghostwindow_destroy(wmWindowManager *wm, wmWindow *win)
{
if (win->ghostwin) {
+ /* Prevents non-drawable state of main windows (bugs #22967,
+ * #25071 and possibly #22477 too). Always clear it even if
+ * this window was not the drawable one, because we mess with
+ * drawing context to discard the GW context. */
+ wm_window_clear_drawable(wm);
+
+ if (win == wm->winactive) {
+ wm->winactive = NULL;
+ }
+
+ /* We need this window's opengl context active to discard it. */
+ GHOST_ActivateWindowDrawingContext(win->ghostwin);
+ GWN_context_active_set(win->gwnctx);
+
+ /* Delete local gawain objects. */
+ GWN_context_discard(win->gwnctx);
+
GHOST_DisposeWindow(g_system, win->ghostwin);
win->ghostwin = NULL;
- win->multisamples = 0;
+ win->gwnctx = NULL;
+
}
}
@@ -186,10 +221,7 @@ void wm_window_free(bContext *C, wmWindowManager *wm, wmWindow *win)
CTX_wm_window_set(C, NULL);
}
- /* always set drawable and active to NULL,
- * prevents non-drawable state of main windows (bugs #22967 and #25071, possibly #22477 too) */
- wm->windrawable = NULL;
- wm->winactive = NULL;
+ BKE_screen_area_map_free(&win->global_areas);
/* end running jobs, a job end also removes its timer */
for (wt = wm->timers.first; wt; wt = wtnext) {
@@ -207,13 +239,15 @@ void wm_window_free(bContext *C, wmWindowManager *wm, wmWindow *win)
if (win->eventstate) MEM_freeN(win->eventstate);
- wm_event_free_all(win);
- wm_subwindows_free(win);
+ if (win->cursor_keymap_status) {
+ MEM_freeN(win->cursor_keymap_status);
+ }
- wm_draw_data_free(win);
+ wm_event_free_all(win);
- wm_ghostwindow_destroy(win);
+ wm_ghostwindow_destroy(wm, win);
+ BKE_workspace_instance_hook_free(G_MAIN, win->workspace_hook);
MEM_freeN(win->stereo3d_format);
MEM_freeN(win);
@@ -232,42 +266,42 @@ static int find_free_winid(wmWindowManager *wm)
}
/* don't change context itself */
-wmWindow *wm_window_new(bContext *C)
+wmWindow *wm_window_new(bContext *C, wmWindow *parent)
{
+ Main *bmain = CTX_data_main(C);
wmWindowManager *wm = CTX_wm_manager(C);
wmWindow *win = MEM_callocN(sizeof(wmWindow), "window");
BLI_addtail(&wm->windows, win);
win->winid = find_free_winid(wm);
+ win->parent = (parent && parent->parent) ? parent->parent : parent;
win->stereo3d_format = MEM_callocN(sizeof(Stereo3dFormat), "Stereo 3D Format (window)");
+ win->workspace_hook = BKE_workspace_instance_hook_create(bmain);
return win;
}
-
/* part of wm_window.c api */
-wmWindow *wm_window_copy(bContext *C, wmWindow *win_src)
+wmWindow *wm_window_copy(bContext *C, wmWindow *win_src, const bool duplicate_layout, const bool child)
{
Main *bmain = CTX_data_main(C);
- wmWindow *win_dst = wm_window_new(C);
+ wmWindow *win_parent = (child) ? win_src : win_src->parent;
+ wmWindow *win_dst = wm_window_new(C, win_parent);
+ WorkSpace *workspace = WM_window_get_active_workspace(win_src);
+ WorkSpaceLayout *layout_old = WM_window_get_active_layout(win_src);
+ WorkSpaceLayout *layout_new;
win_dst->posx = win_src->posx + 10;
win_dst->posy = win_src->posy;
win_dst->sizex = win_src->sizex;
win_dst->sizey = win_src->sizey;
- /* duplicate assigns to window */
- win_dst->screen = ED_screen_duplicate(bmain, win_dst, win_src->screen);
- BLI_strncpy(win_dst->screenname, win_dst->screen->id.name + 2, sizeof(win_dst->screenname));
- win_dst->screen->winid = win_dst->winid;
-
- win_dst->screen->do_refresh = true;
- win_dst->screen->do_draw = true;
-
- win_dst->drawmethod = U.wmdrawmethod;
-
- BLI_listbase_clear(&win_dst->drawdata);
+ win_dst->scene = win_src->scene;
+ STRNCPY(win_dst->view_layer_name, win_src->view_layer_name);
+ BKE_workspace_active_set(win_dst->workspace_hook, workspace);
+ layout_new = duplicate_layout ? ED_workspace_layout_duplicate(bmain, workspace, layout_old, win_dst) : layout_old;
+ BKE_workspace_hook_layout_for_workspace_set(win_dst->workspace_hook, workspace, layout_new);
*win_dst->stereo3d_format = *win_src->stereo3d_format;
@@ -278,12 +312,12 @@ wmWindow *wm_window_copy(bContext *C, wmWindow *win_src)
* A higher level version of copy that tests the new window can be added.
* (called from the operator directly)
*/
-wmWindow *wm_window_copy_test(bContext *C, wmWindow *win_src)
+wmWindow *wm_window_copy_test(bContext *C, wmWindow *win_src, const bool duplicate_layout, const bool child)
{
wmWindowManager *wm = CTX_wm_manager(C);
wmWindow *win_dst;
- win_dst = wm_window_copy(C, win_src);
+ win_dst = wm_window_copy(C, win_src, duplicate_layout, child);
WM_check(C);
@@ -449,50 +483,59 @@ void wm_quit_with_optional_confirmation_prompt(bContext *C, wmWindow *win)
/* this is event from ghost, or exit-blender op */
void wm_window_close(bContext *C, wmWindowManager *wm, wmWindow *win)
{
- wmWindow *tmpwin;
-
- /* first check if we have to quit (there are non-temp remaining windows) */
- for (tmpwin = wm->windows.first; tmpwin; tmpwin = tmpwin->next) {
- if (tmpwin == win)
- continue;
- if (tmpwin->screen->temp == 0)
+ /* First check if there is another main window remaining. */
+ wmWindow *win_other;
+ for (win_other = wm->windows.first; win_other; win_other = win_other->next) {
+ if (win_other != win &&
+ win_other->parent == NULL &&
+ !WM_window_is_temp_screen(win_other))
+ {
break;
+ }
}
- if (tmpwin == NULL) {
+ if (win->parent == NULL && win_other == NULL) {
wm_quit_with_optional_confirmation_prompt(C, win);
+ return;
}
- else {
- /* We're just closing a window */
- bScreen *screen = win->screen;
- BLI_remlink(&wm->windows, win);
+ /* close child windows */
+ for (wmWindow *win_child = wm->windows.first; win_child; win_child = win_child->next) {
+ if (win_child->parent == win) {
+ wm_window_close(C, wm, win_child);
+ }
+ }
- wm_draw_window_clear(win);
+ bScreen *screen = WM_window_get_active_screen(win);
+ WorkSpace *workspace = WM_window_get_active_workspace(win);
+ WorkSpaceLayout *layout = BKE_workspace_active_layout_get(win->workspace_hook);
- CTX_wm_window_set(C, win); /* needed by handlers */
- WM_event_remove_handlers(C, &win->handlers);
- WM_event_remove_handlers(C, &win->modalhandlers);
+ BLI_remlink(&wm->windows, win);
- /* for regular use this will _never_ be NULL,
- * however we may be freeing an improperly initialized window. */
- if (win->screen) {
- ED_screen_exit(C, win, win->screen);
- }
+ CTX_wm_window_set(C, win); /* needed by handlers */
+ WM_event_remove_handlers(C, &win->handlers);
+ WM_event_remove_handlers(C, &win->modalhandlers);
- wm_window_free(C, wm, win);
+ /* for regular use this will _never_ be NULL,
+ * however we may be freeing an improperly initialized window. */
+ if (screen) {
+ ED_screen_exit(C, win, screen);
+ }
- /* if temp screen, delete it after window free (it stops jobs that can access it) */
- if (screen && screen->temp) {
- Main *bmain = CTX_data_main(C);
- BKE_libblock_free(bmain, screen);
- }
+ wm_window_free(C, wm, win);
+
+ /* if temp screen, delete it after window free (it stops jobs that can access it) */
+ if (screen && screen->temp) {
+ Main *bmain = CTX_data_main(C);
+
+ BLI_assert(BKE_workspace_layout_screen_get(layout) == screen);
+ BKE_workspace_layout_remove(bmain, workspace, layout);
}
}
void wm_window_title(wmWindowManager *wm, wmWindow *win)
{
- if (win->screen && win->screen->temp) {
+ if (WM_window_is_temp_screen(win)) {
/* nothing to do for 'temp' windows,
* because WM_window_open_temp always sets window title */
}
@@ -556,26 +599,29 @@ void WM_window_set_dpi(wmWindow *win)
U.dpi = dpi / pixelsize;
U.virtual_pixel = (pixelsize == 1) ? VIRTUAL_PIXEL_NATIVE : VIRTUAL_PIXEL_DOUBLE;
U.widget_unit = (U.pixelsize * U.dpi * 20 + 36) / 72;
+ U.dpi_fac = ((U.pixelsize * (float)U.dpi) / 72.0f);
/* update font drawing */
BLF_default_dpi(U.pixelsize * U.dpi);
}
+static void wm_window_ensure_eventstate(wmWindow *win)
+{
+ if (win->eventstate) {
+ return;
+ }
+
+ win->eventstate = MEM_callocN(sizeof(wmEvent), "window event state");
+ wm_get_cursor_position(win, &win->eventstate->x, &win->eventstate->y);
+}
+
/* belongs to below */
static void wm_window_ghostwindow_add(wmWindowManager *wm, const char *title, wmWindow *win)
{
GHOST_WindowHandle ghostwin;
GHOST_GLSettings glSettings = {0};
- static int multisamples = -1;
int scr_w, scr_h, posy;
- /* force setting multisamples only once, it requires restart - and you cannot
- * mix it, either all windows have it, or none (tested in OSX opengl) */
- if (multisamples == -1)
- multisamples = U.ogl_multisamples;
-
- glSettings.numOfAASamples = multisamples;
-
/* a new window is created when pageflip mode is required for a window */
if (win->stereo3d_format->display_mode == S3D_DISPLAY_PAGEFLIP)
glSettings.flags |= GHOST_glStereoVisual;
@@ -596,20 +642,23 @@ static void wm_window_ghostwindow_add(wmWindowManager *wm, const char *title, wm
if (ghostwin) {
GHOST_RectangleHandle bounds;
- /* the new window has already been made drawable upon creation */
- wm->windrawable = win;
+ /* Clear drawable so we can set the new window. */
+ wm_window_clear_drawable(wm);
+
+ win->gwnctx = GWN_context_create();
/* needed so we can detect the graphics card below */
GPU_init();
+ /* Set window as drawable upon creation. Note this has already been
+ * it has already been activated by GHOST_CreateWindow. */
+ bool activate = false;
+ wm_window_set_drawable(wm, win, activate);
+
win->ghostwin = ghostwin;
GHOST_SetWindowUserData(ghostwin, win); /* pointer back */
- if (win->eventstate == NULL)
- win->eventstate = MEM_callocN(sizeof(wmEvent), "window event state");
-
- /* store multisamples window was created with, in case user prefs change */
- win->multisamples = multisamples;
+ wm_window_ensure_eventstate(win);
/* store actual window size in blender window */
bounds = GHOST_GetClientBounds(win->ghostwin);
@@ -640,7 +689,6 @@ static void wm_window_ghostwindow_add(wmWindowManager *wm, const char *title, wm
//GHOST_SetWindowState(ghostwin, GHOST_kWindowStateModified);
/* standard state vars for window */
- glEnable(GL_SCISSOR_TEST);
GPU_state_init();
}
}
@@ -715,8 +763,7 @@ void wm_window_ghostwindows_ensure(wmWindowManager *wm)
wm_window_ghostwindow_add(wm, "Blender", win);
}
/* happens after fileread */
- if (win->eventstate == NULL)
- win->eventstate = MEM_callocN(sizeof(wmEvent), "window event state");
+ wm_window_ensure_eventstate(win);
/* add keymap handlers (1 handler for all keys in map!) */
keymap = WM_keymap_find(wm->defaultconf, "Window", 0, 0);
@@ -734,6 +781,11 @@ void wm_window_ghostwindows_ensure(wmWindowManager *wm)
WM_event_add_dropbox_handler(&win->handlers, lb);
}
wm_window_title(wm, win);
+
+ /* add topbar */
+ if (BLI_listbase_is_empty(&win->global_areas.areabase)) {
+ ED_screen_global_areas_create(win);
+ }
}
}
@@ -764,15 +816,13 @@ void wm_window_ghostwindows_remove_invalid(bContext *C, wmWindowManager *wm)
wmWindow *WM_window_open(bContext *C, const rcti *rect)
{
wmWindow *win_prev = CTX_wm_window(C);
- wmWindow *win = wm_window_new(C);
+ wmWindow *win = wm_window_new(C, win_prev);
win->posx = rect->xmin;
win->posy = rect->ymin;
win->sizex = BLI_rcti_size_x(rect);
win->sizey = BLI_rcti_size_y(rect);
- win->drawmethod = U.wmdrawmethod;
-
WM_check(C);
if (win->ghostwin) {
@@ -797,8 +847,10 @@ wmWindow *WM_window_open_temp(bContext *C, int x, int y, int sizex, int sizey, i
Main *bmain = CTX_data_main(C);
wmWindow *win_prev = CTX_wm_window(C);
wmWindow *win;
+ bScreen *screen;
ScrArea *sa;
Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
const char *title;
/* convert to native OS window coordinates */
@@ -820,17 +872,19 @@ wmWindow *WM_window_open_temp(bContext *C, int x, int y, int sizex, int sizey, i
/* test if we have a temp screen already */
for (win = CTX_wm_manager(C)->windows.first; win; win = win->next)
- if (win->screen->temp)
+ if (WM_window_is_temp_screen(win))
break;
/* add new window? */
if (win == NULL) {
- win = wm_window_new(C);
+ win = wm_window_new(C, win_prev);
win->posx = rect.xmin;
win->posy = rect.ymin;
}
+ screen = WM_window_get_active_screen(win);
+
win->sizex = BLI_rcti_size_x(&rect);
win->sizey = BLI_rcti_size_y(&rect);
@@ -839,17 +893,27 @@ wmWindow *WM_window_open_temp(bContext *C, int x, int y, int sizex, int sizey, i
wm_window_raise(win);
}
- if (win->screen == NULL) {
- /* add new screen */
- win->screen = ED_screen_add(bmain, win, scene, "temp");
+ if (WM_window_get_active_workspace(win) == NULL) {
+ WorkSpace *workspace = WM_window_get_active_workspace(win_prev);
+ BKE_workspace_active_set(win->workspace_hook, workspace);
}
- else {
- /* switch scene for rendering */
- if (win->screen->scene != scene)
- ED_screen_set_scene(C, win->screen, scene);
+
+ if (screen == NULL) {
+ /* add new screen layout */
+ WorkSpace *workspace = WM_window_get_active_workspace(win);
+ WorkSpaceLayout *layout = ED_workspace_layout_add(bmain, workspace, win, "temp");
+
+ screen = BKE_workspace_layout_screen_get(layout);
+ WM_window_set_active_layout(win, workspace, layout);
}
- win->screen->temp = 1;
+ /* Set scene and view layer to match original window. */
+ STRNCPY(win->view_layer_name, view_layer->name);
+ if (WM_window_get_active_scene(win) != scene) {
+ ED_screen_scene_change(C, win, scene);
+ }
+
+ screen->temp = 1;
/* make window active, and validate/resize */
CTX_wm_window_set(C, win);
@@ -862,25 +926,35 @@ wmWindow *WM_window_open_temp(bContext *C, int x, int y, int sizex, int sizey, i
*/
/* ensure it shows the right spacetype editor */
- sa = win->screen->areabase.first;
+ sa = screen->areabase.first;
CTX_wm_area_set(C, sa);
if (type == WM_WINDOW_RENDER) {
ED_area_newspace(C, sa, SPACE_IMAGE, false);
}
+ else if (type == WM_WINDOW_DRIVERS) {
+ ED_area_newspace(C, sa, SPACE_IPO, false);
+ }
else {
ED_area_newspace(C, sa, SPACE_USERPREF, false);
}
- ED_screen_set(C, win->screen);
+ ED_screen_change(C, screen);
ED_screen_refresh(CTX_wm_manager(C), win); /* test scale */
+ /* do additional setup for specific editor type */
+ if (type == WM_WINDOW_DRIVERS) {
+ ED_drivers_editor_init(C, sa);
+ }
+
if (sa->spacetype == SPACE_IMAGE)
title = IFACE_("Blender Render");
else if (ELEM(sa->spacetype, SPACE_OUTLINER, SPACE_USERPREF))
title = IFACE_("Blender User Preferences");
else if (sa->spacetype == SPACE_FILE)
title = IFACE_("Blender File View");
+ else if (sa->spacetype == SPACE_IPO)
+ title = IFACE_("Blender Drivers Editor");
else
title = "Blender";
@@ -908,17 +982,25 @@ int wm_window_close_exec(bContext *C, wmOperator *UNUSED(op))
return OPERATOR_FINISHED;
}
-/* operator callback */
-int wm_window_duplicate_exec(bContext *C, wmOperator *UNUSED(op))
+int wm_window_new_exec(bContext *C, wmOperator *UNUSED(op))
{
wmWindow *win_src = CTX_wm_window(C);
bool ok;
- ok = (wm_window_copy_test(C, win_src) != NULL);
+ ok = (wm_window_copy_test(C, win_src, true, true) != NULL);
return ok ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
}
+int wm_window_new_main_exec(bContext *C, wmOperator *UNUSED(op))
+{
+ wmWindow *win_src = CTX_wm_window(C);
+ bool ok;
+
+ ok = (wm_window_copy_test(C, win_src, true, false) != NULL);
+
+ return ok ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
+}
/* fullscreen operator callback */
int wm_window_fullscreen_toggle_exec(bContext *C, wmOperator *UNUSED(op))
@@ -1009,22 +1091,65 @@ static int query_qual(modifierKeyType qual)
return val;
}
+static void wm_window_set_drawable(wmWindowManager *wm, wmWindow *win, bool activate)
+{
+ BLI_assert(ELEM(wm->windrawable, NULL, win));
+
+ wm->windrawable = win;
+ if (activate) {
+ GHOST_ActivateWindowDrawingContext(win->ghostwin);
+ }
+ GWN_context_active_set(win->gwnctx);
+ immActivate();
+}
+
+static void wm_window_clear_drawable(wmWindowManager *wm)
+{
+ if (wm->windrawable) {
+ BLF_batch_reset();
+ gpu_batch_presets_reset();
+ immDeactivate();
+ wm->windrawable = NULL;
+ }
+}
+
void wm_window_make_drawable(wmWindowManager *wm, wmWindow *win)
{
+ BLI_assert(GPU_framebuffer_current_get() == 0);
+
if (win != wm->windrawable && win->ghostwin) {
// win->lmbut = 0; /* keeps hanging when mousepressed while other window opened */
+ wm_window_clear_drawable(wm);
- wm->windrawable = win;
if (G.debug & G_DEBUG_EVENTS) {
printf("%s: set drawable %d\n", __func__, win->winid);
}
- GHOST_ActivateWindowDrawingContext(win->ghostwin);
+
+ wm_window_set_drawable(wm, win, true);
/* this can change per window */
WM_window_set_dpi(win);
}
}
+/* Reset active the current window opengl drawing context. */
+void wm_window_reset_drawable(void)
+{
+ BLI_assert(BLI_thread_is_main());
+ BLI_assert(GPU_framebuffer_current_get() == 0);
+ wmWindowManager *wm = G_MAIN->wm.first;
+
+ if (wm == NULL)
+ return;
+
+ wmWindow *win = wm->windrawable;
+
+ if (win && win->ghostwin) {
+ wm_window_clear_drawable(wm);
+ wm_window_set_drawable(wm, win, true);
+ }
+}
+
/* called by ghost, here we handle events for windows themselves or send to event system */
/* mouse coordinate converversion happens here */
static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr)
@@ -1044,7 +1169,7 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr
/* Ghost now can call this function for life resizes, but it should return if WM didn't initialize yet.
* Can happen on file read (especially full size window) */
- if ((wm->initialized & WM_INIT_WINDOW) == 0) {
+ if ((wm->initialized & WM_WINDOW_IS_INITIALIZED) == 0) {
return 1;
}
if (!ghostwin) {
@@ -1248,6 +1373,8 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr
win->posx != posx ||
win->posy != posy)
{
+ const bScreen *screen = WM_window_get_active_screen(win);
+
win->sizex = sizex;
win->sizey = sizey;
win->posx = posx;
@@ -1283,7 +1410,7 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr
}
wm_window_make_drawable(wm, win);
- wm_draw_window_clear(win);
+ BKE_icon_changed(screen->id.icon_id);
WM_event_add_notifier(C, NC_SCREEN | NA_EDITED, NULL);
WM_event_add_notifier(C, NC_WINDOW | NA_EDITED, NULL);
@@ -1395,6 +1522,8 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr
WM_window_set_dpi(win);
if (U.pixelsize != prev_pixelsize) {
+ BKE_icon_changed(WM_window_get_active_screen(win)->id.icon_id);
+
// close all popups since they are positioned with the pixel
// size baked in and it's difficult to correct them
wmWindow *oldWindow = CTX_wm_window(C);
@@ -1403,7 +1532,6 @@ static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr C_void_ptr
CTX_wm_window_set(C, oldWindow);
wm_window_make_drawable(wm, win);
- wm_draw_window_clear(win);
WM_event_add_notifier(C, NC_SCREEN | NA_EDITED, NULL);
WM_event_add_notifier(C, NC_WINDOW | NA_EDITED, NULL);
@@ -1534,13 +1662,22 @@ void wm_window_testbreak(void)
/* **************** init ********************** */
+/* bContext can be null in background mode because we don't
+ * need to event handling. */
void wm_ghost_init(bContext *C)
{
if (!g_system) {
- GHOST_EventConsumerHandle consumer = GHOST_CreateEventConsumer(ghost_event_proc, C);
+ GHOST_EventConsumerHandle consumer;
+
+ if (C != NULL) {
+ consumer = GHOST_CreateEventConsumer(ghost_event_proc, C);
+ }
g_system = GHOST_CreateSystem();
- GHOST_AddEventConsumer(g_system, consumer);
+
+ if (C != NULL) {
+ GHOST_AddEventConsumer(g_system, consumer);
+ }
if (wm_init_state.native_pixels) {
GHOST_UseNativePixels();
@@ -1784,14 +1921,9 @@ void wm_window_raise(wmWindow *win)
void wm_window_swap_buffers(wmWindow *win)
{
-
-#ifdef WIN32
- glDisable(GL_SCISSOR_TEST);
+ GPU_texture_orphans_delete(); /* XXX should be done elsewhere. */
+ GPU_material_orphans_delete(); /* XXX Amen to that. */
GHOST_SwapWindowBuffers(win->ghostwin);
- glEnable(GL_SCISSOR_TEST);
-#else
- GHOST_SwapWindowBuffers(win->ghostwin);
-#endif
}
void wm_window_set_swap_interval (wmWindow *win, int interval)
@@ -1882,19 +2014,73 @@ float WM_cursor_pressure(const struct wmWindow *win)
/* support for native pixel size */
/* mac retina opens window in size X, but it has up to 2 x more pixels */
-int WM_window_pixels_x(wmWindow *win)
+int WM_window_pixels_x(const wmWindow *win)
{
float f = GHOST_GetNativePixelSize(win->ghostwin);
return (int)(f * (float)win->sizex);
}
-
-int WM_window_pixels_y(wmWindow *win)
+int WM_window_pixels_y(const wmWindow *win)
{
float f = GHOST_GetNativePixelSize(win->ghostwin);
return (int)(f * (float)win->sizey);
+}
+/**
+ * Get boundaries usable by all window contents, including global areas.
+ */
+void WM_window_rect_calc(const wmWindow *win, rcti *r_rect)
+{
+ BLI_rcti_init(r_rect, 0, WM_window_pixels_x(win), 0, WM_window_pixels_y(win));
+}
+/**
+ * Get boundaries usable by screen-layouts, excluding global areas.
+ * \note Depends on U.dpi_fac. Should that be outdated, call #WM_window_set_dpi first.
+ */
+void WM_window_screen_rect_calc(const wmWindow *win, rcti *r_rect)
+{
+ rcti window_rect, screen_rect;
+
+ WM_window_rect_calc(win, &window_rect);
+ screen_rect = window_rect;
+
+ /* Substract global areas from screen rectangle. */
+ for (ScrArea *global_area = win->global_areas.areabase.first; global_area; global_area = global_area->next) {
+ int height = ED_area_global_size_y(global_area) - 1;
+
+ if (global_area->global->flag & GLOBAL_AREA_IS_HIDDEN) {
+ continue;
+ }
+
+ switch (global_area->global->align) {
+ case GLOBAL_AREA_ALIGN_TOP:
+ if ((screen_rect.ymax - height) > window_rect.ymin) {
+ height += U.pixelsize;
+ }
+ if (screen_rect.ymax < (window_rect.ymax - 1)) {
+ height += U.pixelsize;
+ }
+ screen_rect.ymax -= height;
+ break;
+ case GLOBAL_AREA_ALIGN_BOTTOM:
+ if (screen_rect.ymin > window_rect.ymin) {
+ height += U.pixelsize;
+ }
+ if ((screen_rect.ymin + height) < (window_rect.ymax - 1)) {
+ height += U.pixelsize;
+ }
+ screen_rect.ymin += height;
+ break;
+ default:
+ BLI_assert(0);
+ break;
+ }
+ }
+
+ BLI_assert(screen_rect.xmin < screen_rect.xmax);
+ BLI_assert(screen_rect.ymin < screen_rect.ymax);
+ *r_rect = screen_rect;
}
bool WM_window_is_fullscreen(wmWindow *win)
@@ -1902,6 +2088,169 @@ bool WM_window_is_fullscreen(wmWindow *win)
return win->windowstate == GHOST_kWindowStateFullScreen;
}
+/**
+ * Some editor data may need to be synced with scene data (3D View camera and layers).
+ * This function ensures data is synced for editors in visible workspaces and their visible layouts.
+ */
+void WM_windows_scene_data_sync(const ListBase *win_lb, Scene *scene)
+{
+ for (wmWindow *win = win_lb->first; win; win = win->next) {
+ if (WM_window_get_active_scene(win) == scene) {
+ ED_workspace_scene_data_sync(win->workspace_hook, scene);
+ }
+ }
+}
+
+Scene *WM_windows_scene_get_from_screen(const wmWindowManager *wm, const bScreen *screen)
+{
+ for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ if (WM_window_get_active_screen(win) == screen) {
+ return WM_window_get_active_scene(win);
+ }
+ }
+
+ return NULL;
+}
+
+WorkSpace *WM_windows_workspace_get_from_screen(const wmWindowManager *wm, const bScreen *screen)
+{
+ for (wmWindow *win = wm->windows.first; win; win = win->next) {
+ if (WM_window_get_active_screen(win) == screen) {
+ return WM_window_get_active_workspace(win);
+ }
+ }
+ return NULL;
+}
+
+Scene *WM_window_get_active_scene(const wmWindow *win)
+{
+ return win->scene;
+}
+
+/**
+ * \warning Only call outside of area/region loops
+ */
+void WM_window_set_active_scene(Main *bmain, bContext *C, wmWindow *win, Scene *scene)
+{
+ wmWindowManager *wm = CTX_wm_manager(C);
+ wmWindow *win_parent = (win->parent) ? win->parent : win;
+ bool changed = false;
+
+ /* Set scene in parent and its child windows. */
+ if (win_parent->scene != scene) {
+ ED_screen_scene_change(C, win_parent, scene);
+ changed = true;
+ }
+
+ for (wmWindow *win_child = wm->windows.first; win_child; win_child = win_child->next) {
+ if (win_child->parent == win_parent && win_child->scene != scene) {
+ ED_screen_scene_change(C, win_child, scene);
+ changed = true;
+ }
+ }
+
+ if (changed) {
+ /* Update depsgraph and renderers for scene change. */
+ ViewLayer *view_layer = WM_window_get_active_view_layer(win_parent);
+ ED_scene_change_update(bmain, scene, view_layer);
+
+ /* Complete redraw. */
+ WM_event_add_notifier(C, NC_WINDOW, NULL);
+ }
+}
+
+ViewLayer *WM_window_get_active_view_layer(const wmWindow *win)
+{
+ Scene *scene = WM_window_get_active_scene(win);
+ if (scene == NULL) {
+ return NULL;
+ }
+
+ ViewLayer *view_layer = BKE_view_layer_find(scene, win->view_layer_name);
+ if (view_layer) {
+ return view_layer;
+ }
+
+ return BKE_view_layer_default_view(scene);
+}
+
+void WM_window_set_active_view_layer(wmWindow *win, ViewLayer *view_layer)
+{
+ BLI_assert(BKE_view_layer_find(WM_window_get_active_scene(win), view_layer->name) != NULL);
+
+ wmWindowManager *wm = G_MAIN->wm.first;
+ wmWindow *win_parent = (win->parent) ? win->parent : win;
+
+ /* Set view layer in parent and child windows. */
+ STRNCPY(win->view_layer_name, view_layer->name);
+
+ for (wmWindow *win_child = wm->windows.first; win_child; win_child = win_child->next) {
+ if (win_child->parent == win_parent) {
+ STRNCPY(win_child->view_layer_name, view_layer->name);
+ }
+ }
+}
+
+void WM_window_ensure_active_view_layer(wmWindow *win)
+{
+ /* Update layer name is correct after scene changes, load without UI, etc. */
+ Scene *scene = WM_window_get_active_scene(win);
+
+ if (scene && BKE_view_layer_find(scene, win->view_layer_name) == NULL) {
+ ViewLayer *view_layer = BKE_view_layer_default_view(scene);
+ STRNCPY(win->view_layer_name, view_layer->name);
+ }
+}
+
+WorkSpace *WM_window_get_active_workspace(const wmWindow *win)
+{
+ return BKE_workspace_active_get(win->workspace_hook);
+}
+
+void WM_window_set_active_workspace(bContext *C, wmWindow *win, WorkSpace *workspace)
+{
+ wmWindowManager *wm = CTX_wm_manager(C);
+ wmWindow *win_parent = (win->parent) ? win->parent : win;
+
+ ED_workspace_change(workspace, C, wm, win);
+
+ for (wmWindow *win_child = wm->windows.first; win_child; win_child = win_child->next) {
+ if (win_child->parent == win_parent) {
+ ED_workspace_change(workspace, C, wm, win_child);
+ }
+ }
+}
+
+WorkSpaceLayout *WM_window_get_active_layout(const wmWindow *win)
+{
+ const WorkSpace *workspace = WM_window_get_active_workspace(win);
+ return (LIKELY(workspace != NULL) ? BKE_workspace_active_layout_get(win->workspace_hook) : NULL);
+}
+void WM_window_set_active_layout(wmWindow *win, WorkSpace *workspace, WorkSpaceLayout *layout)
+{
+ BKE_workspace_hook_layout_for_workspace_set(win->workspace_hook, workspace, layout);
+}
+
+/**
+ * Get the active screen of the active workspace in \a win.
+ */
+bScreen *WM_window_get_active_screen(const wmWindow *win)
+{
+ const WorkSpace *workspace = WM_window_get_active_workspace(win);
+ /* May be NULL in rare cases like closing Blender */
+ return (LIKELY(workspace != NULL) ? BKE_workspace_active_screen_get(win->workspace_hook) : NULL);
+}
+void WM_window_set_active_screen(wmWindow *win, WorkSpace *workspace, bScreen *screen)
+{
+ BKE_workspace_active_screen_set(win->workspace_hook, workspace, screen);
+}
+
+bool WM_window_is_temp_screen(const wmWindow *win)
+{
+ const bScreen *screen = WM_window_get_active_screen(win);
+ return (screen && screen->temp != 0);
+}
+
#ifdef WITH_INPUT_IME
/* note: keep in mind wm_window_IME_begin is also used to reposition the IME window */
@@ -1920,3 +2269,34 @@ void wm_window_IME_end(wmWindow *win)
win->ime_data = NULL;
}
#endif /* WITH_INPUT_IME */
+
+/* ****** direct opengl context management ****** */
+
+void *WM_opengl_context_create(void)
+{
+ /* On Windows there is a problem creating contexts that share lists
+ * from one context that is current in another thread.
+ * So we should call this function only on the main thread.
+ */
+ BLI_assert(BLI_thread_is_main());
+ BLI_assert(GPU_framebuffer_current_get() == 0);
+ return GHOST_CreateOpenGLContext(g_system);
+}
+
+void WM_opengl_context_dispose(void *context)
+{
+ BLI_assert(GPU_framebuffer_current_get() == 0);
+ GHOST_DisposeOpenGLContext(g_system, (GHOST_ContextHandle)context);
+}
+
+void WM_opengl_context_activate(void *context)
+{
+ BLI_assert(GPU_framebuffer_current_get() == 0);
+ GHOST_ActivateOpenGLContext((GHOST_ContextHandle)context);
+}
+
+void WM_opengl_context_release(void *context)
+{
+ BLI_assert(GPU_framebuffer_current_get() == 0);
+ GHOST_ReleaseOpenGLContext((GHOST_ContextHandle)context);
+}