2 * ***** BEGIN GPL LICENSE BLOCK *****
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software Foundation,
16 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 * The Original Code is Copyright (C) 2007 Blender Foundation but based
19 * on ghostwinlay.c (C) 2001-2002 by NaN Holding BV
20 * All rights reserved.
22 * Contributor(s): Blender Foundation, 2008
24 * ***** END GPL LICENSE BLOCK *****
27 /** \file blender/windowmanager/intern/wm_window.c
37 #include "DNA_listBase.h"
38 #include "DNA_screen_types.h"
39 #include "DNA_windowmanager_types.h"
40 #include "RNA_access.h"
42 #include "MEM_guardedalloc.h"
44 #include "GHOST_C-api.h"
46 #include "BLI_blenlib.h"
47 #include "BLI_utildefines.h"
49 #include "BLF_translation.h"
51 #include "BKE_blender.h"
52 #include "BKE_context.h"
53 #include "BKE_library.h"
54 #include "BKE_global.h"
64 #include "wm_window.h"
65 #include "wm_subwindow.h"
66 #include "wm_event_system.h"
68 #include "ED_screen.h"
69 #include "ED_fileselect.h"
74 #include "GPU_extensions.h"
76 #include "UI_interface.h"
78 /* the global to talk to ghost */
79 static GHOST_SystemHandle g_system = NULL;
81 typedef enum WinOverrideFlag {
82 WIN_OVERRIDE_GEOM = (1 << 0),
83 WIN_OVERRIDE_WINSTATE = (1 << 1)
86 /* set by commandline */
87 static struct WMInitStruct {
93 WinOverrideFlag override_flag;
94 } wm_init_state = {0, 0, 0, 0, GHOST_kWindowStateNormal, 0};
96 /* ******** win open & close ************ */
98 /* XXX this one should correctly check for apple top header...
99 * done for Cocoa : returns window contents (and not frame) max size*/
100 void wm_get_screensize(int *width_r, int *height_r)
102 unsigned int uiwidth;
103 unsigned int uiheight;
105 GHOST_GetMainDisplayDimensions(g_system, &uiwidth, &uiheight);
107 *height_r = uiheight;
110 /* keeps offset and size within monitor bounds */
111 /* XXX solve dual screen... */
112 static void wm_window_check_position(rcti *rect)
114 int width, height, d;
116 wm_get_screensize(&width, &height);
118 #if defined(__APPLE__) && !defined(GHOST_COCOA)
122 if (rect->xmin < 0) {
123 rect->xmax -= rect->xmin;
126 if (rect->ymin < 0) {
127 rect->ymax -= rect->ymin;
130 if (rect->xmax > width) {
131 d = rect->xmax - width;
135 if (rect->ymax > height) {
136 d = rect->ymax - height;
141 if (rect->xmin < 0) rect->xmin = 0;
142 if (rect->ymin < 0) rect->ymin = 0;
146 static void wm_ghostwindow_destroy(wmWindow *win)
149 GHOST_DisposeWindow(g_system, win->ghostwin);
150 win->ghostwin = NULL;
154 /* including window itself, C can be NULL.
155 * ED_screen_exit should have been called */
156 void wm_window_free(bContext *C, wmWindowManager *wm, wmWindow *win)
158 wmTimer *wt, *wtnext;
162 WM_event_remove_handlers(C, &win->handlers);
163 WM_event_remove_handlers(C, &win->modalhandlers);
165 if (CTX_wm_window(C) == win)
166 CTX_wm_window_set(C, NULL);
169 /* always set drawable and active to NULL,
170 * prevents non-drawable state of main windows (bugs #22967 and #25071, possibly #22477 too) */
171 wm->windrawable = NULL;
172 wm->winactive = NULL;
174 /* end running jobs, a job end also removes its timer */
175 for (wt = wm->timers.first; wt; wt = wtnext) {
177 if (wt->win == win && wt->event_type == TIMERJOBS)
178 wm_jobs_timer_ended(wm, wt);
181 /* timer removing, need to call this api function */
182 for (wt = wm->timers.first; wt; wt = wtnext) {
185 WM_event_remove_timer(wm, win, wt);
188 if (win->eventstate) MEM_freeN(win->eventstate);
190 wm_event_free_all(win);
191 wm_subwindows_free(win);
194 MEM_freeN(win->drawdata);
196 wm_ghostwindow_destroy(win);
201 static int find_free_winid(wmWindowManager *wm)
206 for (win = wm->windows.first; win; win = win->next)
207 if (id <= win->winid)
213 /* don't change context itself */
214 wmWindow *wm_window_new(bContext *C)
216 wmWindowManager *wm = CTX_wm_manager(C);
217 wmWindow *win = MEM_callocN(sizeof(wmWindow), "window");
219 BLI_addtail(&wm->windows, win);
220 win->winid = find_free_winid(wm);
226 /* part of wm_window.c api */
227 wmWindow *wm_window_copy(bContext *C, wmWindow *winorig)
229 wmWindow *win = wm_window_new(C);
231 win->posx = winorig->posx + 10;
232 win->posy = winorig->posy;
233 win->sizex = winorig->sizex;
234 win->sizey = winorig->sizey;
236 /* duplicate assigns to window */
237 win->screen = ED_screen_duplicate(win, winorig->screen);
238 BLI_strncpy(win->screenname, win->screen->id.name + 2, sizeof(win->screenname));
239 win->screen->winid = win->winid;
241 win->screen->do_refresh = 1;
242 win->screen->do_draw = 1;
244 win->drawmethod = -1;
245 win->drawdata = NULL;
250 /* this is event from ghost, or exit-blender op */
251 void wm_window_close(bContext *C, wmWindowManager *wm, wmWindow *win)
254 bScreen *screen = win->screen;
256 /* first check if we have any non-temp remaining windows */
257 if ((U.uiflag & USER_QUIT_PROMPT) && !wm->file_saved) {
258 if (wm->windows.first) {
259 for (tmpwin = wm->windows.first; tmpwin; tmpwin = tmpwin->next) {
262 if (tmpwin->screen->temp == 0)
265 if (tmpwin == NULL) {
266 if (!GHOST_confirmQuit(win->ghostwin))
272 BLI_remlink(&wm->windows, win);
274 wm_draw_window_clear(win);
275 CTX_wm_window_set(C, win); /* needed by handlers */
276 WM_event_remove_handlers(C, &win->handlers);
277 WM_event_remove_handlers(C, &win->modalhandlers);
278 ED_screen_exit(C, win, win->screen);
280 wm_window_free(C, wm, win);
282 /* if temp screen, delete it after window free (it stops jobs that can access it) */
284 Main *bmain = CTX_data_main(C);
285 BKE_libblock_free(&bmain->screen, screen);
288 /* check remaining windows */
289 if (wm->windows.first) {
290 for (win = wm->windows.first; win; win = win->next)
291 if (win->screen->temp == 0)
293 /* in this case we close all */
301 void wm_window_title(wmWindowManager *wm, wmWindow *win)
303 /* handle the 'temp' window, only set title when not set before */
304 if (win->screen && win->screen->temp) {
305 char *title = GHOST_GetTitle(win->ghostwin);
306 if (title == NULL || title[0] == 0)
307 GHOST_SetTitle(win->ghostwin, "Blender");
311 /* this is set to 1 if you don't have startup.blend open */
312 if (G.save_over && G.main->name[0]) {
313 char str[sizeof(G.main->name) + 12];
314 BLI_snprintf(str, sizeof(str), "Blender%s [%s]", wm->file_saved ? "" : "*", G.main->name);
315 GHOST_SetTitle(win->ghostwin, str);
318 GHOST_SetTitle(win->ghostwin, "Blender");
320 /* Informs GHOST of unsaved changes, to set window modified visual indicator (MAC OS X)
321 * and to give hint of unsaved changes for a user warning mechanism
322 * in case of OS application terminate request (e.g. OS Shortcut Alt+F4, Cmd+Q, (...), or session end) */
323 GHOST_SetWindowModifiedState(win->ghostwin, (GHOST_TUns8) !wm->file_saved);
325 #if defined(__APPLE__) && !defined(GHOST_COCOA)
327 GHOST_SetWindowState(win->ghostwin, GHOST_kWindowStateUnModified);
329 GHOST_SetWindowState(win->ghostwin, GHOST_kWindowStateModified);
334 /* belongs to below */
335 static void wm_window_add_ghostwindow(const char *title, wmWindow *win)
337 GHOST_WindowHandle ghostwin;
338 int scr_w, scr_h, posy;
340 wm_get_screensize(&scr_w, &scr_h);
341 posy = (scr_h - win->posy - win->sizey);
343 #if defined(__APPLE__) && !defined(GHOST_COCOA)
345 extern int macPrefState; /* creator.c */
346 initial_state += macPrefState;
349 /* Disable AA for now, as GL_SELECT (used for border, lasso, ... select)
350 * doesn't work well when AA is initialized, even if not used. */
351 ghostwin = GHOST_CreateWindow(g_system, title,
352 win->posx, posy, win->sizex, win->sizey,
353 (GHOST_TWindowState)win->windowstate,
354 GHOST_kDrawingContextTypeOpenGL,
359 /* needed so we can detect the graphics card below */
360 GPU_extensions_init();
363 GHOST_SetWindowState(ghostwin, (GHOST_TWindowState)win->windowstate);
365 win->ghostwin = ghostwin;
366 GHOST_SetWindowUserData(ghostwin, win); /* pointer back */
368 if (win->eventstate == NULL)
369 win->eventstate = MEM_callocN(sizeof(wmEvent), "window event state");
371 /* until screens get drawn, make it nice grey */
372 glClearColor(.55, .55, .55, 0.0);
373 /* Crash on OSS ATI: bugs.launchpad.net/ubuntu/+source/mesa/+bug/656100 */
374 if (!GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_UNIX, GPU_DRIVER_OPENSOURCE)) {
375 glClear(GL_COLOR_BUFFER_BIT);
378 wm_window_swap_buffers(win);
380 //GHOST_SetWindowState(ghostwin, GHOST_kWindowStateModified);
382 /* standard state vars for window */
383 glEnable(GL_SCISSOR_TEST);
389 /* for wmWindows without ghostwin, open these and clear */
390 /* window size is read from window, if 0 it uses prefsize */
391 /* called in WM_check, also inits stuff after file read */
392 void wm_window_add_ghostwindows(wmWindowManager *wm)
397 /* no commandline prefsize? then we set this.
398 * Note that these values will be used only
399 * when there is no startup.blend yet.
401 if (wm_init_state.size_x == 0) {
402 wm_get_screensize(&wm_init_state.size_x, &wm_init_state.size_y);
404 #if defined(__APPLE__) && !defined(GHOST_COCOA)
405 //Cocoa provides functions to get correct max window size
407 extern void wm_set_apple_prefsize(int, int); /* wm_apple.c */
409 wm_set_apple_prefsize(wm_init_state.size_x, wm_init_state.size_y);
412 wm_init_state.start_x = 0;
413 wm_init_state.start_y = 0;
418 for (win = wm->windows.first; win; win = win->next) {
419 if (win->ghostwin == NULL) {
420 if ((win->sizex == 0) || (wm_init_state.override_flag & WIN_OVERRIDE_GEOM)) {
421 win->posx = wm_init_state.start_x;
422 win->posy = wm_init_state.start_y;
423 win->sizex = wm_init_state.size_x;
424 win->sizey = wm_init_state.size_y;
425 wm_init_state.override_flag &= ~WIN_OVERRIDE_GEOM;
428 if (wm_init_state.override_flag & WIN_OVERRIDE_WINSTATE) {
429 win->windowstate = wm_init_state.windowstate;
430 wm_init_state.override_flag &= ~WIN_OVERRIDE_WINSTATE;
433 wm_window_add_ghostwindow("Blender", win);
435 /* happens after fileread */
436 if (win->eventstate == NULL)
437 win->eventstate = MEM_callocN(sizeof(wmEvent), "window event state");
439 /* add keymap handlers (1 handler for all keys in map!) */
440 keymap = WM_keymap_find(wm->defaultconf, "Window", 0, 0);
441 WM_event_add_keymap_handler(&win->handlers, keymap);
443 keymap = WM_keymap_find(wm->defaultconf, "Screen", 0, 0);
444 WM_event_add_keymap_handler(&win->handlers, keymap);
446 keymap = WM_keymap_find(wm->defaultconf, "Screen Editing", 0, 0);
447 WM_event_add_keymap_handler(&win->modalhandlers, keymap);
451 ListBase *lb = WM_dropboxmap_find("Window", 0, 0);
452 WM_event_add_dropbox_handler(&win->handlers, lb);
454 wm_window_title(wm, win);
458 /* new window, no screen yet, but we open ghostwindow for it */
459 /* also gets the window level handlers */
460 /* area-rip calls this */
461 wmWindow *WM_window_open(bContext *C, rcti *rect)
463 wmWindow *win = wm_window_new(C);
465 win->posx = rect->xmin;
466 win->posy = rect->ymin;
467 win->sizex = rect->xmax - rect->xmin;
468 win->sizey = rect->ymax - rect->ymin;
470 win->drawmethod = -1;
471 win->drawdata = NULL;
478 /* uses screen->temp tag to define what to do, currently it limits
479 * to only one "temp" window for render out, preferences, filewindow, etc */
480 /* type is #define in WM_api.h */
482 void WM_window_open_temp(bContext *C, rcti *position, int type)
487 /* changes rect to fit within desktop */
488 wm_window_check_position(position);
490 /* test if we have a temp screen already */
491 for (win = CTX_wm_manager(C)->windows.first; win; win = win->next)
492 if (win->screen->temp)
495 /* add new window? */
497 win = wm_window_new(C);
499 win->posx = position->xmin;
500 win->posy = position->ymin;
503 win->sizex = position->xmax - position->xmin;
504 win->sizey = position->ymax - position->ymin;
507 wm_window_set_size(win, win->sizex, win->sizey);
508 wm_window_raise(win);
511 /* add new screen? */
512 if (win->screen == NULL)
513 win->screen = ED_screen_add(win, CTX_data_scene(C), "temp");
514 win->screen->temp = 1;
516 /* make window active, and validate/resize */
517 CTX_wm_window_set(C, win);
520 /* ensure it shows the right spacetype editor */
521 sa = win->screen->areabase.first;
522 CTX_wm_area_set(C, sa);
524 if (type == WM_WINDOW_RENDER) {
525 ED_area_newspace(C, sa, SPACE_IMAGE);
528 ED_area_newspace(C, sa, SPACE_USERPREF);
531 ED_screen_set(C, win->screen);
533 if (sa->spacetype == SPACE_IMAGE)
534 GHOST_SetTitle(win->ghostwin, IFACE_("Blender Render"));
535 else if (ELEM(sa->spacetype, SPACE_OUTLINER, SPACE_USERPREF))
536 GHOST_SetTitle(win->ghostwin, IFACE_("Blender User Preferences"));
537 else if (sa->spacetype == SPACE_FILE)
538 GHOST_SetTitle(win->ghostwin, IFACE_("Blender File View"));
540 GHOST_SetTitle(win->ghostwin, "Blender");
544 /* ****************** Operators ****************** */
546 /* operator callback */
547 int wm_window_duplicate_exec(bContext *C, wmOperator *UNUSED(op))
549 wm_window_copy(C, CTX_wm_window(C));
552 WM_event_add_notifier(C, NC_WINDOW | NA_ADDED, NULL);
554 return OPERATOR_FINISHED;
558 /* fullscreen operator callback */
559 int wm_window_fullscreen_toggle_exec(bContext *C, wmOperator *UNUSED(op))
561 wmWindow *window = CTX_wm_window(C);
562 GHOST_TWindowState state;
565 return OPERATOR_CANCELLED;
567 state = GHOST_GetWindowState(window->ghostwin);
568 if (state != GHOST_kWindowStateFullScreen)
569 GHOST_SetWindowState(window->ghostwin, GHOST_kWindowStateFullScreen);
571 GHOST_SetWindowState(window->ghostwin, GHOST_kWindowStateNormal);
573 return OPERATOR_FINISHED;
578 /* ************ events *************** */
588 /* check if specified modifier key type is pressed */
589 static int query_qual(modifierKeyType qual)
591 GHOST_TModifierKeyMask left, right;
596 left = GHOST_kModifierKeyLeftShift;
597 right = GHOST_kModifierKeyRightShift;
600 left = GHOST_kModifierKeyLeftControl;
601 right = GHOST_kModifierKeyRightControl;
604 left = right = GHOST_kModifierKeyOS;
608 left = GHOST_kModifierKeyLeftAlt;
609 right = GHOST_kModifierKeyRightAlt;
613 GHOST_GetModifierKeyState(g_system, left, &val);
615 GHOST_GetModifierKeyState(g_system, right, &val);
620 void wm_window_make_drawable(bContext *C, wmWindow *win)
622 wmWindowManager *wm = CTX_wm_manager(C);
624 if (win != wm->windrawable && win->ghostwin) {
625 // win->lmbut= 0; /* keeps hanging when mousepressed while other window opened */
627 wm->windrawable = win;
628 if (G.debug & G_DEBUG_EVENTS) {
629 printf("%s: set drawable %d\n", __func__, win->winid);
631 GHOST_ActivateWindowDrawingContext(win->ghostwin);
635 /* called by ghost, here we handle events for windows themselves or send to event system */
636 static int ghost_event_proc(GHOST_EventHandle evt, GHOST_TUserDataPtr private)
638 bContext *C = private;
639 wmWindowManager *wm = CTX_wm_manager(C);
640 GHOST_TEventType type = GHOST_GetEventType(evt);
641 int time = GHOST_GetEventTime(evt);
643 if (type == GHOST_kEventQuit) {
647 GHOST_WindowHandle ghostwin = GHOST_GetEventWindow(evt);
648 GHOST_TEventDataPtr data = GHOST_GetEventData(evt);
652 // XXX - should be checked, why are we getting an event here, and
654 puts("<!> event has no window");
657 else if (!GHOST_ValidWindow(g_system, ghostwin)) {
658 // XXX - should be checked, why are we getting an event here, and
660 puts("<!> event has invalid window");
664 win = GHOST_GetWindowUserData(ghostwin);
668 case GHOST_kEventWindowDeactivate:
669 wm_event_add_ghostevent(wm, win, type, time, data);
670 win->active = 0; /* XXX */
672 case GHOST_kEventWindowActivate:
674 GHOST_TEventKeyData kdata;
677 wm->winactive = win; /* no context change! c->wm->windrawable is drawable, or for area queues */
680 // window_handle(win, INPUTCHANGE, win->active);
682 /* bad ghost support for modifier keys... so on activate we set the modifiers again */
684 kdata.utf8_buf[0] = '\0';
685 if (win->eventstate->shift && !query_qual(SHIFT)) {
686 kdata.key = GHOST_kKeyLeftShift;
687 wm_event_add_ghostevent(wm, win, GHOST_kEventKeyUp, time, &kdata);
689 if (win->eventstate->ctrl && !query_qual(CONTROL)) {
690 kdata.key = GHOST_kKeyLeftControl;
691 wm_event_add_ghostevent(wm, win, GHOST_kEventKeyUp, time, &kdata);
693 if (win->eventstate->alt && !query_qual(ALT)) {
694 kdata.key = GHOST_kKeyLeftAlt;
695 wm_event_add_ghostevent(wm, win, GHOST_kEventKeyUp, time, &kdata);
697 if (win->eventstate->oskey && !query_qual(OS)) {
698 kdata.key = GHOST_kKeyOS;
699 wm_event_add_ghostevent(wm, win, GHOST_kEventKeyUp, time, &kdata);
701 /* keymodifier zero, it hangs on hotkeys that open windows otherwise */
702 win->eventstate->keymodifier = 0;
704 /* entering window, update mouse pos. but no event */
705 GHOST_GetCursorPosition(g_system, &wx, &wy);
707 GHOST_ScreenToClient(win->ghostwin, wx, wy, &cx, &cy);
708 win->eventstate->x = cx;
709 win->eventstate->y = (win->sizey - 1) - cy;
711 win->addmousemove = 1; /* enables highlighted buttons */
713 wm_window_make_drawable(C, win);
716 case GHOST_kEventWindowClose: {
717 wm_window_close(C, wm, win);
720 case GHOST_kEventWindowUpdate: {
721 if (G.debug & G_DEBUG_EVENTS) {
722 printf("%s: ghost redraw %d\n", __func__, win->winid);
725 wm_window_make_drawable(C, win);
726 WM_event_add_notifier(C, NC_WINDOW, NULL);
730 case GHOST_kEventWindowSize:
731 case GHOST_kEventWindowMove: {
732 GHOST_TWindowState state;
733 state = GHOST_GetWindowState(win->ghostwin);
734 win->windowstate = state;
736 /* win32: gives undefined window size when minimized */
737 if (state != GHOST_kWindowStateMinimized) {
738 GHOST_RectangleHandle client_rect;
739 int l, t, r, b, scr_w, scr_h;
740 int sizex, sizey, posx, posy;
742 client_rect = GHOST_GetClientBounds(win->ghostwin);
743 GHOST_GetRectangle(client_rect, &l, &t, &r, &b);
745 GHOST_DisposeRectangle(client_rect);
747 wm_get_screensize(&scr_w, &scr_h);
751 posy = scr_h - t - win->sizey;
754 * Ghost sometimes send size or move events when the window hasn't changed.
755 * One case of this is using compiz on linux. To alleviate the problem
756 * we ignore all such event here.
758 * It might be good to eventually do that at Ghost level, but that is for
761 if (win->sizex != sizex ||
762 win->sizey != sizey ||
772 if (G.debug & G_DEBUG_EVENTS) {
773 const char *state_str;
774 state = GHOST_GetWindowState(win->ghostwin);
776 if (state == GHOST_kWindowStateNormal) {
777 state_str = "normal";
779 else if (state == GHOST_kWindowStateMinimized) {
780 state_str = "minimized";
782 else if (state == GHOST_kWindowStateMaximized) {
783 state_str = "maximized";
785 else if (state == GHOST_kWindowStateFullScreen) {
786 state_str = "fullscreen";
789 state_str = "<unknown>";
792 printf("%s: window %d state = %s\n", __func__, win->winid, state_str);
794 if (type != GHOST_kEventWindowSize) {
795 printf("win move event pos %d %d size %d %d\n",
796 win->posx, win->posy, win->sizex, win->sizey);
800 wm_window_make_drawable(C, win);
801 wm_draw_window_clear(win);
802 WM_event_add_notifier(C, NC_SCREEN | NA_EDITED, NULL);
803 WM_event_add_notifier(C, NC_WINDOW | NA_EDITED, NULL);
809 case GHOST_kEventOpenMainFile:
811 PointerRNA props_ptr;
813 char *path = GHOST_GetEventData(evt);
816 /* operator needs a valid window in context, ensures
817 * it is correctly set */
818 oldWindow = CTX_wm_window(C);
819 CTX_wm_window_set(C, win);
821 WM_operator_properties_create(&props_ptr, "WM_OT_open_mainfile");
822 RNA_string_set(&props_ptr, "filepath", path);
823 WM_operator_name_call(C, "WM_OT_open_mainfile", WM_OP_EXEC_DEFAULT, &props_ptr);
824 WM_operator_properties_free(&props_ptr);
826 CTX_wm_window_set(C, oldWindow);
830 case GHOST_kEventDraggingDropDone:
833 GHOST_TEventDragnDropData *ddd = GHOST_GetEventData(evt);
836 /* entering window, update mouse pos */
837 GHOST_GetCursorPosition(g_system, &wx, &wy);
839 GHOST_ScreenToClient(win->ghostwin, wx, wy, &cx, &cy);
840 win->eventstate->x = cx;
841 win->eventstate->y = (win->sizey - 1) - cy;
843 event = *(win->eventstate); /* copy last state, like mouse coords */
846 event.type = MOUSEMOVE;
847 event.prevx = event.x;
848 event.prevy = event.y;
850 wm->winactive = win; /* no context change! c->wm->windrawable is drawable, or for area queues */
853 wm_event_add(win, &event);
856 /* make blender drop event with custom data pointing to wm drags */
857 event.type = EVT_DROP;
858 event.val = KM_RELEASE;
859 event.custom = EVT_DATA_LISTBASE;
860 event.customdata = &wm->drags;
861 event.customdatafree = 1;
863 wm_event_add(win, &event);
865 /* printf("Drop detected\n"); */
867 /* add drag data to wm for paths: */
869 if (ddd->dataType == GHOST_kDragnDropTypeFilenames) {
870 GHOST_TStringArray *stra = ddd->data;
873 for (a = 0; a < stra->count; a++) {
874 printf("drop file %s\n", stra->strings[a]);
875 /* try to get icon type from extension */
876 icon = ED_file_extension_icon((char *)stra->strings[a]);
878 WM_event_start_drag(C, icon, WM_DRAG_PATH, stra->strings[a], 0.0);
879 /* void poin should point to string, it makes a copy */
880 break; // only one drop element supported now
890 wm_event_add_ghostevent(wm, win, type, time, data);
899 /* This timer system only gives maximum 1 timer event per redraw cycle,
900 * to prevent queues to get overloaded.
901 * Timer handlers should check for delta to decide if they just
902 * update, or follow real time.
903 * Timer handlers can also set duration to match frames passed
905 static int wm_window_timer(const bContext *C)
907 wmWindowManager *wm = CTX_wm_manager(C);
908 wmTimer *wt, *wtnext;
910 double time = PIL_check_seconds_timer();
913 for (wt = wm->timers.first; wt; wt = wtnext) {
914 wtnext = wt->next; /* in case timer gets removed */
918 if (time > wt->ntime) {
919 wt->delta = time - wt->ltime;
920 wt->duration += wt->delta;
922 wt->ntime = wt->stime + wt->timestep *ceil(wt->duration / wt->timestep);
924 if (wt->event_type == TIMERJOBS)
925 wm_jobs_timer(C, wm, wt);
926 else if (wt->event_type == TIMERAUTOSAVE)
927 wm_autosave_timer(C, wm, wt);
929 wmEvent event = *(win->eventstate);
931 event.type = wt->event_type;
932 event.custom = EVT_DATA_TIMER;
933 event.customdata = wt;
934 wm_event_add(win, &event);
944 void wm_window_process_events(const bContext *C)
946 int hasevent = GHOST_ProcessEvents(g_system, 0); /* 0 is no wait */
949 GHOST_DispatchEvents(g_system);
951 hasevent |= wm_window_timer(C);
953 /* no event, we sleep 5 milliseconds */
958 void wm_window_process_events_nosleep(void)
960 if (GHOST_ProcessEvents(g_system, 0))
961 GHOST_DispatchEvents(g_system);
964 /* exported as handle callback to bke blender.c */
965 void wm_window_testbreak(void)
967 static double ltime = 0;
968 double curtime = PIL_check_seconds_timer();
970 /* only check for breaks every 50 milliseconds
971 * if we get called more often.
973 if ((curtime - ltime) > .05) {
974 int hasevent = GHOST_ProcessEvents(g_system, 0); /* 0 is no wait */
977 GHOST_DispatchEvents(g_system);
983 /* **************** init ********************** */
985 void wm_ghost_init(bContext *C)
988 GHOST_EventConsumerHandle consumer = GHOST_CreateEventConsumer(ghost_event_proc, C);
990 g_system = GHOST_CreateSystem();
991 GHOST_AddEventConsumer(g_system, consumer);
995 void wm_ghost_exit(void)
998 GHOST_DisposeSystem(g_system);
1003 /* **************** timer ********************** */
1005 /* to (de)activate running timers temporary */
1006 void WM_event_timer_sleep(wmWindowManager *wm, wmWindow *UNUSED(win), wmTimer *timer, int dosleep)
1010 for (wt = wm->timers.first; wt; wt = wt->next)
1015 wt->sleep = dosleep;
1018 wmTimer *WM_event_add_timer(wmWindowManager *wm, wmWindow *win, int event_type, double timestep)
1020 wmTimer *wt = MEM_callocN(sizeof(wmTimer), "window timer");
1022 wt->event_type = event_type;
1023 wt->ltime = PIL_check_seconds_timer();
1024 wt->ntime = wt->ltime + timestep;
1025 wt->stime = wt->ltime;
1026 wt->timestep = timestep;
1029 BLI_addtail(&wm->timers, wt);
1034 void WM_event_remove_timer(wmWindowManager *wm, wmWindow *UNUSED(win), wmTimer *timer)
1038 /* extra security check */
1039 for (wt = wm->timers.first; wt; wt = wt->next)
1043 if (wm->reports.reporttimer == wt)
1044 wm->reports.reporttimer = NULL;
1046 BLI_remlink(&wm->timers, wt);
1048 MEM_freeN(wt->customdata);
1053 /* ******************* clipboard **************** */
1055 char *WM_clipboard_text_get(int selection)
1057 char *p, *p2, *buf, *newbuf;
1062 buf = (char *)GHOST_getClipboard(selection);
1066 /* always convert from \r\n to \n */
1067 newbuf = MEM_callocN(strlen(buf) + 1, "WM_clipboard_text_get");
1069 for (p = buf, p2 = newbuf; *p; p++) {
1075 free(buf); /* ghost uses regular malloc */
1080 void WM_clipboard_text_set(char *buf, int selection)
1082 if (!G.background) {
1084 /* do conversion from \n to \r\n on Windows */
1085 char *p, *p2, *newbuf;
1088 for (p = buf; *p; p++) {
1095 newbuf = MEM_callocN(newlen + 1, "WM_clipboard_text_set");
1097 for (p = buf, p2 = newbuf; *p; p++, p2++) {
1099 *(p2++) = '\r'; *p2 = '\n';
1105 GHOST_putClipboard((GHOST_TInt8 *)newbuf, selection);
1108 GHOST_putClipboard((GHOST_TInt8 *)buf, selection);
1113 /* ******************* progress bar **************** */
1115 void WM_progress_set(wmWindow *win, float progress)
1117 GHOST_SetProgressBar(win->ghostwin, progress);
1120 void WM_progress_clear(wmWindow *win)
1122 GHOST_EndProgressBar(win->ghostwin);
1125 /* ************************************ */
1127 void wm_window_get_position(wmWindow *win, int *posx_r, int *posy_r)
1129 *posx_r = win->posx;
1130 *posy_r = win->posy;
1133 void wm_window_get_size(wmWindow *win, int *width_r, int *height_r)
1135 *width_r = win->sizex;
1136 *height_r = win->sizey;
1139 /* exceptional case: - splash is called before events are processed
1140 * this means we don't actually know the window size so get this from GHOST */
1141 void wm_window_get_size_ghost(wmWindow *win, int *width_r, int *height_r)
1143 GHOST_RectangleHandle bounds = GHOST_GetClientBounds(win->ghostwin);
1144 *width_r = GHOST_GetWidthRectangle(bounds);
1145 *height_r = GHOST_GetHeightRectangle(bounds);
1147 GHOST_DisposeRectangle(bounds);
1150 void wm_window_set_size(wmWindow *win, int width, int height)
1152 GHOST_SetClientSize(win->ghostwin, width, height);
1155 void wm_window_lower(wmWindow *win)
1157 GHOST_SetWindowOrder(win->ghostwin, GHOST_kWindowOrderBottom);
1160 void wm_window_raise(wmWindow *win)
1162 GHOST_SetWindowOrder(win->ghostwin, GHOST_kWindowOrderTop);
1165 void wm_window_swap_buffers(wmWindow *win)
1169 glDisable(GL_SCISSOR_TEST);
1170 GHOST_SwapWindowBuffers(win->ghostwin);
1171 glEnable(GL_SCISSOR_TEST);
1173 GHOST_SwapWindowBuffers(win->ghostwin);
1177 void wm_get_cursor_position(wmWindow *win, int *x, int *y)
1179 GHOST_GetCursorPosition(g_system, x, y);
1180 GHOST_ScreenToClient(win->ghostwin, *x, *y, x, y);
1181 *y = (win->sizey - 1) - *y;
1184 /* ******************* exported api ***************** */
1187 /* called whem no ghost system was initialized */
1188 void WM_setprefsize(int stax, int stay, int sizx, int sizy)
1190 wm_init_state.start_x = stax; /* left hand pos */
1191 wm_init_state.start_y = stay; /* bottom pos */
1192 wm_init_state.size_x = sizx;
1193 wm_init_state.size_y = sizy;
1194 wm_init_state.override_flag |= WIN_OVERRIDE_GEOM;
1197 /* for borderless and border windows set from command-line */
1198 void WM_setinitialstate_fullscreen(void)
1200 wm_init_state.windowstate = GHOST_kWindowStateFullScreen;
1201 wm_init_state.override_flag |= WIN_OVERRIDE_WINSTATE;
1204 void WM_setinitialstate_normal(void)
1206 wm_init_state.windowstate = GHOST_kWindowStateNormal;
1207 wm_init_state.override_flag |= WIN_OVERRIDE_WINSTATE;
1210 /* This function requires access to the GHOST_SystemHandle (g_system) */
1211 void WM_cursor_warp(wmWindow *win, int x, int y)
1213 if (win && win->ghostwin) {
1214 int oldx = x, oldy = y;
1216 y = win->sizey - y - 1;
1218 GHOST_ClientToScreen(win->ghostwin, x, y, &x, &y);
1219 GHOST_SetCursorPosition(g_system, x, y);
1221 win->eventstate->prevx = oldx;
1222 win->eventstate->prevy = oldy;