diff options
-rw-r--r-- | src/app.c | 25 | ||||
-rw-r--r-- | src/ui/window.c | 221 | ||||
-rw-r--r-- | src/ui/window.h | 34 | ||||
-rw-r--r-- | src/win32.c | 53 | ||||
-rw-r--r-- | src/win32.h | 6 |
5 files changed, 283 insertions, 56 deletions
@@ -160,12 +160,12 @@ static iString *serializePrefs_App_(const iApp *d) { | |||
160 | const iSidebarWidget *sidebar2 = findWidget_App("sidebar2"); | 160 | const iSidebarWidget *sidebar2 = findWidget_App("sidebar2"); |
161 | appendFormat_String(str, "window.retain arg:%d\n", d->prefs.retainWindowSize); | 161 | appendFormat_String(str, "window.retain arg:%d\n", d->prefs.retainWindowSize); |
162 | if (d->prefs.retainWindowSize) { | 162 | if (d->prefs.retainWindowSize) { |
163 | const iBool isMaximized = (SDL_GetWindowFlags(d->window->win) & SDL_WINDOW_MAXIMIZED) != 0; | 163 | const iBool isMaximized = snap_Window(d->window) == maximized_WindowSnap; |
164 | int w, h, x, y; | 164 | int w, h, x, y; |
165 | x = d->window->lastRect.pos.x; | 165 | x = d->window->place.normalRect.pos.x; |
166 | y = d->window->lastRect.pos.y; | 166 | y = d->window->place.normalRect.pos.y; |
167 | w = d->window->lastRect.size.x; | 167 | w = d->window->place.normalRect.size.x; |
168 | h = d->window->lastRect.size.y; | 168 | h = d->window->place.normalRect.size.y; |
169 | appendFormat_String(str, "window.setrect width:%d height:%d coord:%d %d\n", w, h, x, y); | 169 | appendFormat_String(str, "window.setrect width:%d height:%d coord:%d %d\n", w, h, x, y); |
170 | appendFormat_String(str, "sidebar.width arg:%d\n", width_SidebarWidget(sidebar)); | 170 | appendFormat_String(str, "sidebar.width arg:%d\n", width_SidebarWidget(sidebar)); |
171 | appendFormat_String(str, "sidebar2.width arg:%d\n", width_SidebarWidget(sidebar2)); | 171 | appendFormat_String(str, "sidebar2.width arg:%d\n", width_SidebarWidget(sidebar2)); |
@@ -1113,22 +1113,17 @@ iBool handleCommand_App(const char *cmd) { | |||
1113 | } | 1113 | } |
1114 | else if (equal_Command(cmd, "window.maximize")) { | 1114 | else if (equal_Command(cmd, "window.maximize")) { |
1115 | if (!argLabel_Command(cmd, "toggle")) { | 1115 | if (!argLabel_Command(cmd, "toggle")) { |
1116 | SDL_MaximizeWindow(d->window->win); | 1116 | setSnap_Window(d->window, maximized_WindowSnap); |
1117 | } | 1117 | } |
1118 | else { | 1118 | else { |
1119 | if (SDL_GetWindowFlags(d->window->win) & SDL_WINDOW_MAXIMIZED) { | 1119 | setSnap_Window(d->window, snap_Window(d->window) == maximized_WindowSnap ? 0 : |
1120 | SDL_RestoreWindow(d->window->win); | 1120 | maximized_WindowSnap); |
1121 | } | ||
1122 | else { | ||
1123 | SDL_MaximizeWindow(d->window->win); | ||
1124 | } | ||
1125 | } | 1121 | } |
1126 | return iTrue; | 1122 | return iTrue; |
1127 | } | 1123 | } |
1128 | else if (equal_Command(cmd, "window.fullscreen")) { | 1124 | else if (equal_Command(cmd, "window.fullscreen")) { |
1129 | const iBool wasFull = | 1125 | const iBool wasFull = snap_Window(d->window) == fullscreen_WindowSnap; |
1130 | (SDL_GetWindowFlags(d->window->win) & SDL_WINDOW_FULLSCREEN_DESKTOP) != 0; | 1126 | setSnap_Window(d->window, wasFull ? 0 : fullscreen_WindowSnap); |
1131 | SDL_SetWindowFullscreen(d->window->win, wasFull ? 0 : SDL_WINDOW_FULLSCREEN_DESKTOP); | ||
1132 | postCommandf_App("window.fullscreen.changed arg:%d", !wasFull); | 1127 | postCommandf_App("window.fullscreen.changed arg:%d", !wasFull); |
1133 | return iTrue; | 1128 | return iTrue; |
1134 | } | 1129 | } |
diff --git a/src/ui/window.c b/src/ui/window.c index 6356b292..37586aab 100644 --- a/src/ui/window.c +++ b/src/ui/window.c | |||
@@ -93,15 +93,6 @@ static iBool handleRootCommands_(iWidget *root, const char *cmd) { | |||
93 | setTextColor_LabelWidget(findWidget_App("winbar.title"), uiTextStrong_ColorId); | 93 | setTextColor_LabelWidget(findWidget_App("winbar.title"), uiTextStrong_ColorId); |
94 | return iFalse; | 94 | return iFalse; |
95 | } | 95 | } |
96 | else if (equal_Command(cmd, "window.fullscreen.changed")) { | ||
97 | iWidget *winBar = findWidget_App("winbar"); | ||
98 | if (winBar) { | ||
99 | setFlags_Widget(winBar, hidden_WidgetFlag, arg_Command(cmd)); | ||
100 | arrange_Widget(get_Window()->root); | ||
101 | postRefresh_App(); | ||
102 | } | ||
103 | return iFalse; | ||
104 | } | ||
105 | else if (equal_Command(cmd, "window.minimize")) { | 96 | else if (equal_Command(cmd, "window.minimize")) { |
106 | SDL_MinimizeWindow(get_Window()->win); | 97 | SDL_MinimizeWindow(get_Window()->win); |
107 | return iTrue; | 98 | return iTrue; |
@@ -562,7 +553,7 @@ static void setupUserInterface_Window(iWindow *d) { | |||
562 | setFont_LabelWidget(appButton, uiContentBold_FontId); | 553 | setFont_LabelWidget(appButton, uiContentBold_FontId); |
563 | setId_Widget(addChildFlags_Widget(winBar, | 554 | setId_Widget(addChildFlags_Widget(winBar, |
564 | iClob(appTitle = new_LabelWidget("", NULL)), | 555 | iClob(appTitle = new_LabelWidget("", NULL)), |
565 | expand_WidgetFlag | alignLeft_WidgetFlag | | 556 | expand_WidgetFlag | /*alignLeft_WidgetFlag |*/ |
566 | fixedHeight_WidgetFlag | frameless_WidgetFlag | | 557 | fixedHeight_WidgetFlag | frameless_WidgetFlag | |
567 | commandOnClick_WidgetFlag), | 558 | commandOnClick_WidgetFlag), |
568 | "winbar.title"); | 559 | "winbar.title"); |
@@ -570,7 +561,7 @@ static void setupUserInterface_Window(iWindow *d) { | |||
570 | iLabelWidget *appMin, *appMax, *appClose; | 561 | iLabelWidget *appMin, *appMax, *appClose; |
571 | setId_Widget(addChildFlags_Widget( | 562 | setId_Widget(addChildFlags_Widget( |
572 | winBar, | 563 | winBar, |
573 | iClob(appMin = newLargeIcon_LabelWidget("\u2014", "window.minimize")), | 564 | iClob(appMin = newLargeIcon_LabelWidget("\u2013", "window.minimize")), |
574 | frameless_WidgetFlag), | 565 | frameless_WidgetFlag), |
575 | "winbar.min"); | 566 | "winbar.min"); |
576 | setSize_Widget(as_Widget(appMin), | 567 | setSize_Widget(as_Widget(appMin), |
@@ -582,6 +573,7 @@ static void setupUserInterface_Window(iWindow *d) { | |||
582 | addChildFlags_Widget(winBar, | 573 | addChildFlags_Widget(winBar, |
583 | iClob(appClose = newLargeIcon_LabelWidget("\u2a2f", "window.close")), | 574 | iClob(appClose = newLargeIcon_LabelWidget("\u2a2f", "window.close")), |
584 | frameless_WidgetFlag); | 575 | frameless_WidgetFlag); |
576 | setFont_LabelWidget(appClose, uiContent_FontId); | ||
585 | setSize_Widget(as_Widget(appMax), as_Widget(appMin)->rect.size); | 577 | setSize_Widget(as_Widget(appMax), as_Widget(appMin)->rect.size); |
586 | setSize_Widget(as_Widget(appClose), as_Widget(appMin)->rect.size); | 578 | setSize_Widget(as_Widget(appClose), as_Widget(appMin)->rect.size); |
587 | addChild_Widget(div, iClob(winBar)); | 579 | addChild_Widget(div, iClob(winBar)); |
@@ -744,8 +736,8 @@ static void updateRootSize_Window_(iWindow *d, iBool notifyAlways) { | |||
744 | const iInt2 oldSize = *size; | 736 | const iInt2 oldSize = *size; |
745 | SDL_GetRendererOutputSize(d->render, &size->x, &size->y); | 737 | SDL_GetRendererOutputSize(d->render, &size->x, &size->y); |
746 | if (notifyAlways || !isEqual_I2(oldSize, *size)) { | 738 | if (notifyAlways || !isEqual_I2(oldSize, *size)) { |
747 | const iBool isHoriz = (d->lastNotifiedSize.x != size->x); | 739 | const iBool isHoriz = (d->place.lastNotifiedSize.x != size->x); |
748 | const iBool isVert = (d->lastNotifiedSize.y != size->y); | 740 | const iBool isVert = (d->place.lastNotifiedSize.y != size->y); |
749 | arrange_Widget(d->root); | 741 | arrange_Widget(d->root); |
750 | postCommandf_App("window.resized width:%d height:%d horiz:%d vert:%d", | 742 | postCommandf_App("window.resized width:%d height:%d horiz:%d vert:%d", |
751 | size->x, | 743 | size->x, |
@@ -753,7 +745,7 @@ static void updateRootSize_Window_(iWindow *d, iBool notifyAlways) { | |||
753 | isHoriz, | 745 | isHoriz, |
754 | isVert); | 746 | isVert); |
755 | postRefresh_App(); | 747 | postRefresh_App(); |
756 | d->lastNotifiedSize = *size; | 748 | d->place.lastNotifiedSize = *size; |
757 | } | 749 | } |
758 | } | 750 | } |
759 | 751 | ||
@@ -793,6 +785,9 @@ static void drawBlank_Window_(iWindow *d) { | |||
793 | static SDL_HitTestResult hitTest_Window_(SDL_Window *win, const SDL_Point *pos, void *data) { | 785 | static SDL_HitTestResult hitTest_Window_(SDL_Window *win, const SDL_Point *pos, void *data) { |
794 | iWindow *d = data; | 786 | iWindow *d = data; |
795 | iAssert(d->win == win); | 787 | iAssert(d->win == win); |
788 | if (SDL_GetWindowFlags(d->win) & SDL_WINDOW_MOUSE_CAPTURE) { | ||
789 | return SDL_HITTEST_NORMAL; | ||
790 | } | ||
796 | int w, h; | 791 | int w, h; |
797 | SDL_GetWindowSize(win, &w, &h); | 792 | SDL_GetWindowSize(win, &w, &h); |
798 | /* TODO: Check if inside the caption label widget. */ | 793 | /* TODO: Check if inside the caption label widget. */ |
@@ -802,15 +797,16 @@ static SDL_HitTestResult hitTest_Window_(SDL_Window *win, const SDL_Point *pos, | |||
802 | const iBool isBottom = pos->y >= h - gap_UI; | 797 | const iBool isBottom = pos->y >= h - gap_UI; |
803 | const int captionHeight = lineHeight_Text(uiContent_FontId) + gap_UI * 2; | 798 | const int captionHeight = lineHeight_Text(uiContent_FontId) + gap_UI * 2; |
804 | const int rightEdge = left_Rect(bounds_Widget(findChild_Widget(d->root, "winbar.min"))); | 799 | const int rightEdge = left_Rect(bounds_Widget(findChild_Widget(d->root, "winbar.min"))); |
800 | d->place.lastHit = SDL_HITTEST_NORMAL; | ||
805 | if (isLeft) { | 801 | if (isLeft) { |
806 | return pos->y < captionHeight ? SDL_HITTEST_RESIZE_TOPLEFT | 802 | return pos->y < captionHeight ? SDL_HITTEST_RESIZE_TOPLEFT |
807 | : pos->y > h - captionHeight ? SDL_HITTEST_RESIZE_BOTTOMLEFT | 803 | : pos->y > h - captionHeight ? SDL_HITTEST_RESIZE_BOTTOMLEFT |
808 | : SDL_HITTEST_RESIZE_LEFT; | 804 | : (d->place.lastHit = SDL_HITTEST_RESIZE_LEFT); |
809 | } | 805 | } |
810 | if (isRight) { | 806 | if (isRight) { |
811 | return pos->y < captionHeight ? SDL_HITTEST_RESIZE_TOPRIGHT | 807 | return pos->y < captionHeight ? SDL_HITTEST_RESIZE_TOPRIGHT |
812 | : pos->y > h - captionHeight ? SDL_HITTEST_RESIZE_BOTTOMRIGHT | 808 | : pos->y > h - captionHeight ? SDL_HITTEST_RESIZE_BOTTOMRIGHT |
813 | : SDL_HITTEST_RESIZE_RIGHT; | 809 | : (d->place.lastHit = SDL_HITTEST_RESIZE_RIGHT); |
814 | } | 810 | } |
815 | if (isTop) { | 811 | if (isTop) { |
816 | return pos->x < captionHeight ? SDL_HITTEST_RESIZE_TOPLEFT | 812 | return pos->x < captionHeight ? SDL_HITTEST_RESIZE_TOPLEFT |
@@ -827,6 +823,10 @@ static SDL_HitTestResult hitTest_Window_(SDL_Window *win, const SDL_Point *pos, | |||
827 | } | 823 | } |
828 | return SDL_HITTEST_NORMAL; | 824 | return SDL_HITTEST_NORMAL; |
829 | } | 825 | } |
826 | |||
827 | SDL_HitTestResult hitTest_Window(const iWindow *d, iInt2 pos) { | ||
828 | return hitTest_Window_(d->win, &(SDL_Point){ pos.x, pos.y }, iConstCast(void *, d)); | ||
829 | } | ||
830 | #endif | 830 | #endif |
831 | 831 | ||
832 | iBool create_Window_(iWindow *d, iRect rect, uint32_t flags) { | 832 | iBool create_Window_(iWindow *d, iRect rect, uint32_t flags) { |
@@ -841,7 +841,7 @@ iBool create_Window_(iWindow *d, iRect rect, uint32_t flags) { | |||
841 | } | 841 | } |
842 | #if defined (LAGRANGE_CUSTOM_FRAME) | 842 | #if defined (LAGRANGE_CUSTOM_FRAME) |
843 | /* Register a handler for window hit testing (drag, resize). */ | 843 | /* Register a handler for window hit testing (drag, resize). */ |
844 | SDL_SetWindowHitTest(d->win, hitTest_Window_, d); | 844 | SDL_SetWindowHitTest(d->win, hitTest_Window_, d); |
845 | SDL_SetWindowResizable(d->win, SDL_TRUE); | 845 | SDL_SetWindowResizable(d->win, SDL_TRUE); |
846 | #endif | 846 | #endif |
847 | return iTrue; | 847 | return iTrue; |
@@ -850,12 +850,13 @@ iBool create_Window_(iWindow *d, iRect rect, uint32_t flags) { | |||
850 | void init_Window(iWindow *d, iRect rect) { | 850 | void init_Window(iWindow *d, iRect rect) { |
851 | theWindow_ = d; | 851 | theWindow_ = d; |
852 | iZap(d->cursors); | 852 | iZap(d->cursors); |
853 | d->initialPos = rect.pos; | 853 | d->place.initialPos = rect.pos; |
854 | d->lastRect = rect; | 854 | d->place.normalRect = rect; |
855 | d->lastNotifiedSize = zero_I2(); | 855 | d->place.lastNotifiedSize = zero_I2(); |
856 | d->pendingCursor = NULL; | 856 | d->pendingCursor = NULL; |
857 | d->isDrawFrozen = iTrue; | 857 | d->isDrawFrozen = iTrue; |
858 | d->isExposed = iFalse; | 858 | d->isExposed = iFalse; |
859 | d->isMinimized = iFalse; | ||
859 | d->isMouseInside = iTrue; | 860 | d->isMouseInside = iTrue; |
860 | d->focusGainedAt = 0; | 861 | d->focusGainedAt = 0; |
861 | uint32_t flags = 0; | 862 | uint32_t flags = 0; |
@@ -936,6 +937,9 @@ void init_Window(iWindow *d, iRect rect) { | |||
936 | setupUserInterface_Window(d); | 937 | setupUserInterface_Window(d); |
937 | postCommand_App("bindings.changed"); /* update from bindings */ | 938 | postCommand_App("bindings.changed"); /* update from bindings */ |
938 | updateRootSize_Window_(d, iFalse); | 939 | updateRootSize_Window_(d, iFalse); |
940 | #if defined (LAGRANGE_CUSTOM_FRAME) | ||
941 | SDL_EventState(SDL_SYSWMEVENT, SDL_TRUE); | ||
942 | #endif | ||
939 | } | 943 | } |
940 | 944 | ||
941 | void deinit_Window(iWindow *d) { | 945 | void deinit_Window(iWindow *d) { |
@@ -958,17 +962,8 @@ SDL_Renderer *renderer_Window(const iWindow *d) { | |||
958 | return d->render; | 962 | return d->render; |
959 | } | 963 | } |
960 | 964 | ||
961 | static iBool isMaximized_Window_(const iWindow *d) { | ||
962 | #if !defined (iPlatformApple) | ||
963 | return (SDL_GetWindowFlags(d->win) & (SDL_WINDOW_MINIMIZED | SDL_WINDOW_MAXIMIZED)) != 0; | ||
964 | #else | ||
965 | iUnused(d); | ||
966 | return iFalse; /* There is fullscreen mode but that is not handled at the moment. */ | ||
967 | #endif | ||
968 | } | ||
969 | |||
970 | iBool isFullscreen_Window(const iWindow *d) { | 965 | iBool isFullscreen_Window(const iWindow *d) { |
971 | return (SDL_GetWindowFlags(d->win) & SDL_WINDOW_FULLSCREEN_DESKTOP) != 0; | 966 | return snap_Window(d) == fullscreen_WindowSnap; |
972 | } | 967 | } |
973 | 968 | ||
974 | static void invalidate_Window_(iWindow *d) { | 969 | static void invalidate_Window_(iWindow *d) { |
@@ -976,6 +971,31 @@ static void invalidate_Window_(iWindow *d) { | |||
976 | postCommand_App("theme.changed"); /* forces UI invalidation */ | 971 | postCommand_App("theme.changed"); /* forces UI invalidation */ |
977 | } | 972 | } |
978 | 973 | ||
974 | static iBool isNormalPlacement_Window_(const iWindow *d) { | ||
975 | if (snap_Window(d) || d->isDrawFrozen) return iFalse; | ||
976 | return !(SDL_GetWindowFlags(d->win) & SDL_WINDOW_MINIMIZED); | ||
977 | } | ||
978 | |||
979 | static iBool unsnap_Window_(iWindow *d, const iInt2 *newPos) { | ||
980 | #if defined (LAGRANGE_CUSTOM_FRAME) | ||
981 | const int snap = snap_Window(d); | ||
982 | if (snap == yMaximized_WindowSnap && | ||
983 | (!newPos || (d->place.lastHit == SDL_HITTEST_RESIZE_LEFT || | ||
984 | d->place.lastHit == SDL_HITTEST_RESIZE_RIGHT))) { | ||
985 | return iFalse; | ||
986 | } | ||
987 | if (snap && snap != fullscreen_WindowSnap) { | ||
988 | if (snap_Window(d) == yMaximized_WindowSnap && newPos) { | ||
989 | d->place.normalRect.pos = *newPos; | ||
990 | } | ||
991 | printf("unsnap\n"); fflush(stdout); | ||
992 | setSnap_Window(d, none_WindowSnap); | ||
993 | return iTrue; | ||
994 | } | ||
995 | #endif | ||
996 | return iFalse; | ||
997 | } | ||
998 | |||
979 | static iBool handleWindowEvent_Window_(iWindow *d, const SDL_WindowEvent *ev) { | 999 | static iBool handleWindowEvent_Window_(iWindow *d, const SDL_WindowEvent *ev) { |
980 | switch (ev->event) { | 1000 | switch (ev->event) { |
981 | case SDL_WINDOWEVENT_EXPOSED: | 1001 | case SDL_WINDOWEVENT_EXPOSED: |
@@ -989,33 +1009,62 @@ static iBool handleWindowEvent_Window_(iWindow *d, const SDL_WindowEvent *ev) { | |||
989 | is missing contents until other events trigger a refresh. */ | 1009 | is missing contents until other events trigger a refresh. */ |
990 | postRefresh_App(); | 1010 | postRefresh_App(); |
991 | #if defined (LAGRANGE_ENABLE_WINDOWPOS_FIX) | 1011 | #if defined (LAGRANGE_ENABLE_WINDOWPOS_FIX) |
992 | if (d->initialPos.x >= 0) { | 1012 | if (d->place.initialPos.x >= 0) { |
993 | int bx, by; | 1013 | int bx, by; |
994 | SDL_GetWindowBordersSize(d->win, &by, &bx, NULL, NULL); | 1014 | SDL_GetWindowBordersSize(d->win, &by, &bx, NULL, NULL); |
995 | SDL_SetWindowPosition(d->win, d->initialPos.x + bx, d->initialPos.y + by); | 1015 | SDL_SetWindowPosition(d->win, d->place.initialPos.x + bx, d->place.initialPos.y + by); |
996 | d->initialPos = init1_I2(-1); | 1016 | d->place.initialPos = init1_I2(-1); |
997 | } | 1017 | } |
998 | #endif | 1018 | #endif |
999 | return iFalse; | 1019 | return iFalse; |
1000 | case SDL_WINDOWEVENT_MOVED: { | 1020 | case SDL_WINDOWEVENT_MOVED: { |
1001 | if (!isMaximized_Window_(d) && !isFullscreen_Window(d) && !d->isDrawFrozen) { | 1021 | if (d->isMinimized) { |
1002 | d->lastRect.pos = init_I2(ev->data1, ev->data2); | 1022 | return iFalse; |
1023 | } | ||
1024 | const iInt2 newPos = init_I2(ev->data1, ev->data2); | ||
1025 | if (isEqual_I2(newPos, init1_I2(-32000))) { /* magic! */ | ||
1026 | /* Maybe minimized? Seems like a Windows constant of some kind. */ | ||
1027 | d->isMinimized = iTrue; | ||
1028 | return iFalse; | ||
1029 | } | ||
1030 | //printf("MOVED: %d, %d\n", ev->data1, ev->data2); fflush(stdout); | ||
1031 | if (unsnap_Window_(d, &newPos)) { | ||
1032 | return iTrue; | ||
1033 | } | ||
1034 | if (isNormalPlacement_Window_(d)) { | ||
1035 | d->place.normalRect.pos = newPos; | ||
1036 | //printf("normal rect set (move)\n"); fflush(stdout); | ||
1003 | iInt2 border = zero_I2(); | 1037 | iInt2 border = zero_I2(); |
1004 | #if !defined (iPlatformApple) | 1038 | #if !defined (iPlatformApple) |
1005 | SDL_GetWindowBordersSize(d->win, &border.y, &border.x, NULL, NULL); | 1039 | SDL_GetWindowBordersSize(d->win, &border.y, &border.x, NULL, NULL); |
1006 | #endif | 1040 | #endif |
1007 | d->lastRect.pos = max_I2(zero_I2(), sub_I2(d->lastRect.pos, border)); | 1041 | d->place.normalRect.pos = max_I2(zero_I2(), sub_I2(d->place.normalRect.pos, border)); |
1008 | } | 1042 | } |
1009 | return iTrue; | 1043 | return iTrue; |
1010 | } | 1044 | } |
1011 | case SDL_WINDOWEVENT_RESIZED: | 1045 | case SDL_WINDOWEVENT_RESIZED: |
1012 | if (!isMaximized_Window_(d) && !isFullscreen_Window(d) && !d->isDrawFrozen) { | 1046 | if (d->isMinimized) { |
1013 | d->lastRect.size = init_I2(ev->data1, ev->data2); | 1047 | updateRootSize_Window_(d, iTrue); |
1048 | return iTrue; | ||
1049 | } | ||
1050 | if (unsnap_Window_(d, NULL)) { | ||
1051 | return iTrue; | ||
1052 | } | ||
1053 | if (isNormalPlacement_Window_(d)) { | ||
1054 | d->place.normalRect.size = init_I2(ev->data1, ev->data2); | ||
1055 | //printf("normal rect set (resize)\n"); fflush(stdout); | ||
1014 | } | 1056 | } |
1015 | updateRootSize_Window_(d, iTrue /* we were already redrawing during the resize */); | 1057 | updateRootSize_Window_(d, iTrue /* we were already redrawing during the resize */); |
1016 | return iTrue; | 1058 | return iTrue; |
1017 | case SDL_WINDOWEVENT_RESTORED: | 1059 | case SDL_WINDOWEVENT_RESTORED: |
1060 | //updateRootSize_Window_(d, iTrue); | ||
1018 | invalidate_Window_(d); | 1061 | invalidate_Window_(d); |
1062 | d->isMinimized = iFalse; | ||
1063 | //printf("restored %d\n", snap_Window(d)); fflush(stdout); | ||
1064 | return iTrue; | ||
1065 | case SDL_WINDOWEVENT_MINIMIZED: | ||
1066 | d->isMinimized = iTrue; | ||
1067 | //printf("minimized\n"); fflush(stdout); | ||
1019 | return iTrue; | 1068 | return iTrue; |
1020 | case SDL_WINDOWEVENT_LEAVE: | 1069 | case SDL_WINDOWEVENT_LEAVE: |
1021 | unhover_Widget(); | 1070 | unhover_Widget(); |
@@ -1051,6 +1100,16 @@ static void applyCursor_Window_(iWindow *d) { | |||
1051 | 1100 | ||
1052 | iBool processEvent_Window(iWindow *d, const SDL_Event *ev) { | 1101 | iBool processEvent_Window(iWindow *d, const SDL_Event *ev) { |
1053 | switch (ev->type) { | 1102 | switch (ev->type) { |
1103 | #if defined (LAGRANGE_CUSTOM_FRAME) | ||
1104 | case SDL_SYSWMEVENT: { | ||
1105 | /* We observe native Win32 messages for better user interaction with the | ||
1106 | window frame. Mouse clicks especially will not generate normal SDL | ||
1107 | events if they happen on the custom hit-tested regions. These events | ||
1108 | are processed only there; the UI widgets do not get involved. */ | ||
1109 | processNativeEvent_Win32(ev->syswm.msg, d); | ||
1110 | break; | ||
1111 | } | ||
1112 | #endif | ||
1054 | case SDL_WINDOWEVENT: { | 1113 | case SDL_WINDOWEVENT: { |
1055 | return handleWindowEvent_Window_(d, &ev->window); | 1114 | return handleWindowEvent_Window_(d, &ev->window); |
1056 | } | 1115 | } |
@@ -1232,3 +1291,89 @@ uint32_t frameTime_Window(const iWindow *d) { | |||
1232 | iWindow *get_Window(void) { | 1291 | iWindow *get_Window(void) { |
1233 | return theWindow_; | 1292 | return theWindow_; |
1234 | } | 1293 | } |
1294 | |||
1295 | #if !defined (LAGRANGE_CUSTOM_FRAME) | ||
1296 | void setSnap_Window(iWindow *d, int snapMode) { | ||
1297 | if (snapMode == maximized_WindowSnap) { | ||
1298 | SDL_MaximizeWindow(d->win); | ||
1299 | } | ||
1300 | else if (snapMode == fullscreen_WindowSnap) { | ||
1301 | SDL_SetWindowFullscreen(d->win, SDL_WINDOW_FULLSCREEN_DESKTOP); | ||
1302 | } | ||
1303 | else { | ||
1304 | SDL_RestoreWindow(d->win); | ||
1305 | } | ||
1306 | } | ||
1307 | |||
1308 | int snap_Window(const iWindow *d) { | ||
1309 | const int flags = SDL_GetWindowFlags(d->win); | ||
1310 | if (flags & SDL_WINDOW_FULLSCREEN_DESKTOP) { | ||
1311 | return fullscreen_WindowSnap; | ||
1312 | } | ||
1313 | else if (flags & SDL_WINDOW_MAXIMIZED) { | ||
1314 | return maximized_WindowSnap; | ||
1315 | } | ||
1316 | return none_WindowSnap; | ||
1317 | } | ||
1318 | #endif | ||
1319 | |||
1320 | #if defined (LAGRANGE_CUSTOM_FRAME) | ||
1321 | void setSnap_Window(iWindow *d, int snapMode) { | ||
1322 | if (d->place.snap == snapMode) { | ||
1323 | return; | ||
1324 | } | ||
1325 | iRect newRect = zero_Rect(); | ||
1326 | SDL_Rect usable; | ||
1327 | SDL_GetDisplayUsableBounds(SDL_GetWindowDisplayIndex(d->win), &usable); | ||
1328 | if (d->place.snap == fullscreen_WindowSnap) { | ||
1329 | SDL_SetWindowFullscreen(d->win, 0); | ||
1330 | } | ||
1331 | d->place.snap = snapMode; | ||
1332 | switch (snapMode & mask_WindowSnap) { | ||
1333 | case none_WindowSnap: | ||
1334 | newRect = d->place.normalRect; | ||
1335 | break; | ||
1336 | case left_WindowSnap: | ||
1337 | newRect = init_Rect(usable.x, usable.y, usable.w / 2, usable.h); | ||
1338 | break; | ||
1339 | case right_WindowSnap: | ||
1340 | newRect = init_Rect(usable.x, usable.y + usable.w / 2, usable.w / 2, usable.h); | ||
1341 | break; | ||
1342 | case maximized_WindowSnap: | ||
1343 | newRect = init_Rect(usable.x, usable.y, usable.w, usable.h); | ||
1344 | break; | ||
1345 | case yMaximized_WindowSnap: | ||
1346 | newRect.pos.y = 0; | ||
1347 | newRect.size.y = usable.h; | ||
1348 | SDL_GetWindowPosition(d->win, &newRect.pos.x, NULL); | ||
1349 | SDL_GetWindowSize(d->win, &newRect.size.x, NULL); | ||
1350 | break; | ||
1351 | case fullscreen_WindowSnap: | ||
1352 | SDL_SetWindowFullscreen(d->win, SDL_WINDOW_FULLSCREEN_DESKTOP); | ||
1353 | break; | ||
1354 | } | ||
1355 | if (snapMode & (topBit_WindowSnap | bottomBit_WindowSnap)) { | ||
1356 | newRect.size.y /= 2; | ||
1357 | } | ||
1358 | if (snapMode & bottomBit_WindowSnap) { | ||
1359 | newRect.pos.y += newRect.size.y; | ||
1360 | } | ||
1361 | /* Show and hide the title bar. */ | ||
1362 | iWidget *winBar = findWidget_App("winbar"); | ||
1363 | const iBool wasVisible = isVisible_Widget(winBar); | ||
1364 | setFlags_Widget(winBar, hidden_WidgetFlag, snapMode == fullscreen_WindowSnap); | ||
1365 | if (newRect.size.x) { | ||
1366 | SDL_SetWindowPosition(d->win, newRect.pos.x, newRect.pos.y); | ||
1367 | SDL_SetWindowSize(d->win, newRect.size.x, newRect.size.y); | ||
1368 | postCommand_App("window.resized"); | ||
1369 | } | ||
1370 | if (wasVisible != isVisible_Widget(winBar)) { | ||
1371 | arrange_Widget(d->root); | ||
1372 | postRefresh_App(); | ||
1373 | } | ||
1374 | } | ||
1375 | |||
1376 | int snap_Window(const iWindow *d) { | ||
1377 | return d->place.snap; | ||
1378 | } | ||
1379 | #endif | ||
diff --git a/src/ui/window.h b/src/ui/window.h index 5bde9065..ddb03847 100644 --- a/src/ui/window.h +++ b/src/ui/window.h | |||
@@ -32,13 +32,35 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ | |||
32 | iDeclareType(Window) | 32 | iDeclareType(Window) |
33 | iDeclareTypeConstructionArgs(Window, iRect rect) | 33 | iDeclareTypeConstructionArgs(Window, iRect rect) |
34 | 34 | ||
35 | enum iWindowSnap { | ||
36 | none_WindowSnap = 0, | ||
37 | left_WindowSnap = 1, | ||
38 | right_WindowSnap = 2, | ||
39 | maximized_WindowSnap = 3, | ||
40 | yMaximized_WindowSnap = 4, | ||
41 | fullscreen_WindowSnap = 5, | ||
42 | mask_WindowSnap = 0xff, | ||
43 | topBit_WindowSnap = iBit(9), | ||
44 | bottomBit_WindowSnap = iBit(10), | ||
45 | }; | ||
46 | |||
47 | iDeclareType(WindowPlacement) | ||
48 | |||
49 | /* Tracking of window placement. */ | ||
50 | struct Impl_WindowPlacement { | ||
51 | iInt2 initialPos; | ||
52 | iRect normalRect; /* updated when window is moved/resized */ | ||
53 | iInt2 lastNotifiedSize; /* keep track of horizontal/vertical notifications */ | ||
54 | int snap; /* LAGRANGE_CUSTOM_FRAME */ | ||
55 | int lastHit; | ||
56 | }; | ||
57 | |||
35 | struct Impl_Window { | 58 | struct Impl_Window { |
36 | SDL_Window * win; | 59 | SDL_Window * win; |
37 | iInt2 initialPos; | 60 | iWindowPlacement place; |
38 | iRect lastRect; /* updated when window is moved/resized */ | ||
39 | iInt2 lastNotifiedSize; /* keep track of horizontal/vertical notifications */ | ||
40 | iBool isDrawFrozen; /* avoids premature draws while restoring window state */ | 61 | iBool isDrawFrozen; /* avoids premature draws while restoring window state */ |
41 | iBool isExposed; | 62 | iBool isExposed; |
63 | iBool isMinimized; | ||
42 | iBool isMouseInside; | 64 | iBool isMouseInside; |
43 | uint32_t focusGainedAt; | 65 | uint32_t focusGainedAt; |
44 | SDL_Renderer *render; | 66 | SDL_Renderer *render; |
@@ -60,6 +82,7 @@ void setTitle_Window (iWindow *, const iString *title); | |||
60 | void setUiScale_Window (iWindow *, float uiScale); | 82 | void setUiScale_Window (iWindow *, float uiScale); |
61 | void setFreezeDraw_Window (iWindow *, iBool freezeDraw); | 83 | void setFreezeDraw_Window (iWindow *, iBool freezeDraw); |
62 | void setCursor_Window (iWindow *, int cursor); | 84 | void setCursor_Window (iWindow *, int cursor); |
85 | void setSnap_Window (iWindow *, int snapMode); | ||
63 | 86 | ||
64 | uint32_t id_Window (const iWindow *); | 87 | uint32_t id_Window (const iWindow *); |
65 | iInt2 rootSize_Window (const iWindow *); | 88 | iInt2 rootSize_Window (const iWindow *); |
@@ -68,6 +91,11 @@ iInt2 coord_Window (const iWindow *, int x, int y); | |||
68 | iInt2 mouseCoord_Window (const iWindow *); | 91 | iInt2 mouseCoord_Window (const iWindow *); |
69 | uint32_t frameTime_Window (const iWindow *); | 92 | uint32_t frameTime_Window (const iWindow *); |
70 | SDL_Renderer *renderer_Window (const iWindow *); | 93 | SDL_Renderer *renderer_Window (const iWindow *); |
94 | int snap_Window (const iWindow *); | ||
71 | iBool isFullscreen_Window (const iWindow *); | 95 | iBool isFullscreen_Window (const iWindow *); |
72 | 96 | ||
73 | iWindow * get_Window (void); | 97 | iWindow * get_Window (void); |
98 | |||
99 | #if defined (LAGRANGE_CUSTOM_FRAME) | ||
100 | SDL_HitTestResult hitTest_Window(const iWindow *d, iInt2 pos); | ||
101 | #endif | ||
diff --git a/src/win32.c b/src/win32.c index 5eb2a0d5..585fdaaf 100644 --- a/src/win32.c +++ b/src/win32.c | |||
@@ -21,10 +21,13 @@ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |||
21 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ | 21 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ |
22 | 22 | ||
23 | #include "win32.h" | 23 | #include "win32.h" |
24 | #include "ui/window.h" | ||
25 | #include "app.h" | ||
24 | #include <SDL_syswm.h> | 26 | #include <SDL_syswm.h> |
25 | 27 | ||
26 | #define WIN32_LEAN_AND_MEAN | 28 | #define WIN32_LEAN_AND_MEAN |
27 | #include <Windows.h> | 29 | #include <Windows.h> |
30 | #include <windowsx.h> | ||
28 | #include <d2d1.h> | 31 | #include <d2d1.h> |
29 | 32 | ||
30 | void setDPIAware_Win32(void) { | 33 | void setDPIAware_Win32(void) { |
@@ -59,3 +62,53 @@ void useExecutableIconResource_SDLWindow(SDL_Window *win) { | |||
59 | } | 62 | } |
60 | } | 63 | } |
61 | } | 64 | } |
65 | |||
66 | #if 0 | ||
67 | void setup_SDLWindow(SDL_Window *win) { | ||
68 | SDL_SysWMinfo wmInfo; | ||
69 | SDL_VERSION(&wmInfo.version); | ||
70 | if (SDL_GetWindowWMInfo(win, &wmInfo)) { | ||
71 | HWND hwnd = wmInfo.info.win.window; | ||
72 | // printf("configuring window\n"); | ||
73 | // SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) | WS_SYSMENU); | ||
74 | } | ||
75 | } | ||
76 | #endif | ||
77 | |||
78 | #if defined (LAGRANGE_CUSTOM_FRAME) | ||
79 | void processNativeEvent_Win32(const struct SDL_SysWMmsg *msg, iWindow *window) { | ||
80 | HWND hwnd = msg->msg.win.hwnd; | ||
81 | // printf("[syswm] %x\n", msg->msg.win.msg); fflush(stdout); | ||
82 | switch (msg->msg.win.msg) { | ||
83 | case WM_NCLBUTTONDBLCLK: { | ||
84 | POINT point = { GET_X_LPARAM(msg->msg.win.lParam), GET_Y_LPARAM(msg->msg.win.lParam) }; | ||
85 | ScreenToClient(hwnd, &point); | ||
86 | iInt2 pos = init_I2(point.x, point.y); | ||
87 | switch (hitTest_Window(window, pos)) { | ||
88 | case SDL_HITTEST_DRAGGABLE: | ||
89 | postCommand_App("window.maximize toggle:1"); | ||
90 | break; | ||
91 | case SDL_HITTEST_RESIZE_TOP: | ||
92 | case SDL_HITTEST_RESIZE_BOTTOM: { | ||
93 | setSnap_Window(window, yMaximized_WindowSnap); | ||
94 | break; | ||
95 | } | ||
96 | } | ||
97 | //fflush(stdout); | ||
98 | break; | ||
99 | } | ||
100 | #if 0 | ||
101 | /* SDL does not use WS_SYSMENU on the window, so we can't display the system menu. | ||
102 | However, the only useful function in the menu would be moving-via-keyboard, | ||
103 | but that doesn't work with a custom frame. We could show a custom system menu? */ | ||
104 | case WM_NCRBUTTONUP: { | ||
105 | POINT point = { GET_X_LPARAM(msg->msg.win.lParam), GET_Y_LPARAM(msg->msg.win.lParam) }; | ||
106 | HMENU menu = GetSystemMenu(hwnd, FALSE); | ||
107 | printf("menu at %d,%d menu:%p\n", point.x, point.y, menu); fflush(stdout); | ||
108 | TrackPopupMenu(menu, TPM_RIGHTBUTTON, point.x, point.y, 0, hwnd, NULL); | ||
109 | break; | ||
110 | } | ||
111 | #endif | ||
112 | } | ||
113 | } | ||
114 | #endif /* defined (LAGRANGE_CUSTOM_FRAME) */ | ||
diff --git a/src/win32.h b/src/win32.h index b5bc0b45..b988c302 100644 --- a/src/win32.h +++ b/src/win32.h | |||
@@ -21,8 +21,14 @@ ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |||
21 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ | 21 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ |
22 | 22 | ||
23 | #pragma once | 23 | #pragma once |
24 | |||
25 | #include <the_Foundation/defs.h> | ||
24 | #include <SDL_video.h> | 26 | #include <SDL_video.h> |
27 | #include <SDL_syswm.h> | ||
28 | |||
29 | iDeclareType(Window) | ||
25 | 30 | ||
26 | void setDPIAware_Win32(void); | 31 | void setDPIAware_Win32(void); |
27 | float desktopDPI_Win32(void); | 32 | float desktopDPI_Win32(void); |
28 | void useExecutableIconResource_SDLWindow(SDL_Window *win); | 33 | void useExecutableIconResource_SDLWindow(SDL_Window *win); |
34 | void processNativeEvent_Win32(const struct SDL_SysWMmsg *msg, iWindow *window); | ||