Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » [MASkinG] Nasty dummyDlg

This thread is locked; no one can reply to it. rss feed Print
[MASkinG] Nasty dummyDlg
mail frank
Member #6,213
September 2005

I'm writing a simple desktop game which is a windowed application. I tried openlayer first. It's greate library but it lacks the basic GUI elements. So I shift to MASkinG which can support skin and GUI. Since it supports skin, the MAS::Window has it's own title bar, close button etc, so I mangaged to remove the title bar of Windows. Here is what I did:

1. Create window by Win32 api to set the style to POPUP
2. Pass hwnd to win_set_window
3. Call InstallMASkinG
4. Start my window which inherit from MAS::Window, call Popup(NULL) to show this window.

Everything seems fine, I can move, resize and close window by MASkinG's title bar, except that there is nasty black box behind my window and I can't move around my MASkinG window on whole desktop. I can only move it inside the rectangle which occupied by my MASkinG window. I look into the source code of MASkinG, it seems that a DummyDlg will be created when I call Popup(NULL). This DummyDlg will be the same size of the window and its background is black. My question is that is there a way to move my window like a real windows application?

Please refer to my souce code:

1//////////////////////////////////////////
2// application.cpp
3#include "application.h"
4#include "maindlg.h"
5 
6HINSTANCE hInst = NULL;
7#define WINDOW_WIDTH 478
8#define WINDOW_HEIGHT 358
9 
10CApplication::CApplication()
11{
12}
13 
14CApplication::~CApplication()
15{
16}
17 
18LRESULT CALLBACK WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)
19{
20 switch(Message) {
21 
22 case WM_DESTROY:
23 PostQuitMessage(0);
24 return 0;
25 }
26 
27 return DefWindowProc(hwnd, Message, wParam, lParam);
28}
29 
30bool CApplication::init(HINSTANCE hInstance, HINSTANCE hPrevInstance,
31 LPSTR lpCmdLine, int nCmdShow)
32{
33 static char szAppName[] = "TestWin";
34 WNDCLASS wndClass;
35 RECT win_rect;
36 HWND hwnd;
37 int screen_w, screen_h;
38 
39 hInst = hInstance;
40 
41 if (!hPrevInstance) {
42 wndClass.style = CS_HREDRAW | CS_VREDRAW;
43 wndClass.lpfnWndProc = WndProc;
44 wndClass.cbClsExtra = 0;
45 wndClass.cbWndExtra = 0;
46 wndClass.hInstance = hInst;
47 wndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
48 wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
49 wndClass.hbrBackground = CreateSolidBrush(0);
50 wndClass.lpszClassName = szAppName;
51 
52 RegisterClass(&wndClass);
53 }
54 
55 hwnd = CreateWindow(szAppName, szAppName,
56 WS_POPUP,
57 //WS_OVERLAPPEDWINDOW,
58 CW_USEDEFAULT, CW_USEDEFAULT,
59 WINDOW_WIDTH, WINDOW_HEIGHT,
60 NULL, NULL,
61 hInst, NULL);
62 
63 if (!hwnd) return false;
64 
65 /* get the dimensions of the client area of the window */
66 GetClientRect(hwnd, &win_rect);
67 screen_w = win_rect.right - win_rect.left;
68 screen_h = win_rect.bottom - win_rect.top;
69 
70 /* the DirectX windowed driver requires the width to be a multiple of 4 */
71 screen_w &= ~3;
72 
73 /* register our window BEFORE calling allegro_init() */
74 win_set_window(hwnd);
75 
76 MAS::InstallMASkinG("test.cfg");
77 MAS::ChangeResolution(2,false,screen_w,screen_h,32);
78 
79 /* display the window */
80 ShowWindow(hwnd, nCmdShow);
81 UpdateWindow(hwnd);
82 
83 return true;
84}
85 
86void CApplication::fini()
87{
88 MAS::ExitMASkinG();
89}
90 
91void CApplication::run()
92{
93 CMainDlg *dlg = new CMainDlg(this);
94 dlg->Popup(NULL);
95 //dlg->Execute();
96 delete dlg;
97}
98 
99void CApplication::on_idle()
100{
101 /* process the Win32 messages */
102 if (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE))
103 {
104 if (GetMessage(&msg, NULL, 0, 0))
105 {
106 TranslateMessage(&msg);
107 DispatchMessage(&msg);
108 }
109 }
110}
111 
112///////////////////////////////////////////
113// MainDlg.h
114#include <MASkinG.h>
115 
116class CApplication;
117 
118class CMainDlg : public MAS::Window
119{
120public:
121 CMainDlg(CApplication* pApp);
122 
123protected:
124 
125 void MsgIdle();
126 
127private:
128 CApplication* m_pApp;
129};
130 
131///////////////////////////////////////////
132// MainDlg.cpp
133#include "maindlg.h"
134#include "application.h"
135 
136using namespace MAS;
137 
138CMainDlg::CMainDlg(CApplication* pApp)
139 : m_pApp(pApp)
140{
141 title.SetText("Test Window");
142 //Add(desktop);
143}
144 
145void CMainDlg::MsgIdle()
146{
147 Window::MsgIdle();
148 
149 if (m_pApp)
150 m_pApp->on_idle();
151}

miran
Member #2,407
June 2002

I thought about trying that a while ago but never got round to it. The way I would go about it would be to make the Window occupy the whole screen and make it unmovable (clear some flag, D_MOVABLE or something, I don't remember, check the docs). Then in some way handle the mouse movement when the left mouse button is pressed and the title bar has focus and run the Win32 API code that moves your hwnd instead of the MASkinG window. I have close to zero experience with Win32 API, so I can't help you much there, but I did once make an Allegro app with a custom window with no title bar and all that. I didn't implement moving the window and the app didn't use MASkinG though...

Another thing you should know about is that if the skin you use has transparent parts in the window bitmaps (like rounded corners), those won't actually be transparent, but black...

EDIT:
You can take this as a base. I'm not on Windows right now, so I can't test anything with Win32 API. This code only traps mouse movement on the window title bar.

1#include <MASkinG.h>
2using namespace MAS;
3 
4class MyWindow : public Window {
5 private:
6 Label lblMouseMove;
7 
8 public:
9 MyWindow() : Window() {
10 lblMouseMove.Shape(0, 0, 100, 8);
11 lblMouseMove.ClearFlag(D_AUTOSIZE);
12 lblMouseMove.SetText("---");
13 Add(lblMouseMove);
14 }
15 
16 void HandleEvent(Widget &obj, int msg, int arg1=0, int arg2=0) {
17 Window::HandleEvent(obj, msg, arg1, arg2);
18 
19 if (obj == Window::bGrip || obj == Window::title || obj == Window::textBack) {
20 if (msg == MSG_MOUSEMOVE && (GetMouse()->flags & 1)) {
21 static char buf[16];
22 usprintf(buf, "(%d,%d)", arg1, arg2);
23 lblMouseMove.SetText(buf);
24 }
25 }
26 
27 if (msg == MSG_LRELEASE) {
28 lblMouseMove.SetText("---");
29 }
30 }
31};
32 
33int main() {
34 InstallMASkinG("allegro.cfg");
35 Dialog *dlg = new MyWindow;
36 dlg->ClearFlag(D_MOVABLE | D_RESIZABLE);
37 dlg->Popup();
38 delete dlg;
39 ExitMASkinG();
40 return 0;
41}
42END_OF_MAIN()

--
sig used to be here

mail frank
Member #6,213
September 2005

I've tried win32 api MoveWindow() to move the windows. But there are two problems. First, the black box behind my window doesn't move the same way as my window. Second, it's flickering. I'm just wondering why there are two windows created? Why there is a need to create a DummyDlg?

miran
Member #2,407
June 2002

Quote:

Why there is a need to create a DummyDlg?

Because of the way MASkinG is made. The main loop is in the Dialog::Execute() method and a popup window needs a parent dialog that owns this main loop. So if you popup a Window without a parent dialog, a dummy one has to be created.

See my edit above for a suggestion about how you could handle moving the hwnd window. Put MoveWindow() in place of where I print the move distance to a label in the example...

EDIT:

Quote:

This DummyDlg will be the same size of the window and its background is black.

Hmmm, this should at least have to be possible to turn off. Actually the dummy dialog's backround isn't black, it's a copy of the screen before you call your window's Popup(), which in your case is in fact black. This makes sure that if the window is smaller than the screen, it doesn't leave "droppings" behind when it's moved, but I can easily imagine situations where you'd want to update the background anyway, so the background would just be in the way...

EDIT2:
I'm in Windows now and I managed to get this to work. Here's the full code:

1#include <allegro.h>
2#include <winalleg.h>
3HINSTANCE hInst = NULL;
4 
5bool canMoveWindow = false;
6 
7#include <MASkinG.h>
8 
9class MyWindow : public MAS::Window {
10 protected:
11 void MsgIdle() {
12 MAS::Window::MsgIdle();
13 
14 // process the Win32 messages
15 MSG msg;
16 while (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) {
17 if (GetMessage(&msg, NULL, 0, 0)) {
18 TranslateMessage(&msg);
19 DispatchMessage(&msg);
20 }
21 else {
22 break;
23 }
24 }
25 }
26 
27 public:
28 MyWindow() : MAS::Window() {
29 }
30 
31 void HandleEvent(MAS::Widget &obj, int msg, int arg1=0, int arg2=0) {
32 MAS::Window::HandleEvent(obj, msg, arg1, arg2);
33 
34 if (msg == MSG_MOUSEMOVE) {
35 if (MAS::Window::bGrip.HasMouse() || MAS::Window::title.HasMouse() || MAS::Window::textBack.HasMouse()) {
36 canMoveWindow = true;
37 }
38 else {
39 canMoveWindow = false;
40 }
41 }
42 }
43};
44 
45 
46LRESULT CALLBACK WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)
47{
48 switch(Message) {
49 case WM_COMMAND:
50 switch(LOWORD(wParam)) {
51 }
52 return 0;
53 
54 case WM_NCHITTEST:
55 if (canMoveWindow) {
56 return HTCAPTION;
57 }
58 break;
59 
60 case WM_CLOSE:
61 DestroyWindow(hwnd);
62 return 0;
63 
64 case WM_DESTROY:
65 PostQuitMessage(0);
66 return 0;
67 }
68 
69 return DefWindowProc(hwnd, Message, wParam, lParam);
70}
71 
72 
73 
74int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
75{
76 static char szAppName[] = "Windows Test";
77 WNDCLASS wndClass;
78 RECT win_rect;
79 HWND hwnd;
80 MSG msg;
81 int screen_w, screen_h;
82 
83 hInst = hInstance;
84 
85 if (!hPrevInstance) {
86 wndClass.style = CS_HREDRAW | CS_VREDRAW;
87 wndClass.lpfnWndProc = WndProc;
88 wndClass.cbClsExtra = 0;
89 wndClass.cbWndExtra = 0;
90 wndClass.hInstance = hInst;
91 wndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
92 wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
93 wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
94 wndClass.hbrBackground = CreateSolidBrush(0);
95 wndClass.lpszMenuName = 0;
96 wndClass.lpszClassName = szAppName;
97 
98 RegisterClass(&wndClass);
99 }
100 
101 
102 hwnd = CreateWindow(szAppName, szAppName,
103 WS_POPUP,
104 CW_USEDEFAULT, CW_USEDEFAULT,
105 640, 480,
106 NULL, NULL,
107 hInst, NULL);
108 
109 if (!hwnd) {
110 MessageBoxA(0, "Unable to create the window.", "Error!", MB_ICONERROR | MB_OK | MB_SYSTEMMODAL);
111 return 0;
112 }
113 
114 /* get the dimensions of the client area of the window */
115 GetClientRect(hwnd, &win_rect);
116 screen_w = win_rect.right - win_rect.left;
117 screen_h = win_rect.bottom - win_rect.top;
118 
119 /* the DirectX windowed driver requires the width to be a multiple of 4 */
120 screen_w &= ~3;
121 
122 /* register our window BEFORE calling allegro_init() */
123 win_set_window(hwnd);
124 
125 MAS::InstallMASkinG("allegro.cfg");
126 MAS::ChangeResolution(2,false,screen_w,screen_h,32);
127 
128 /* display the window */
129 ShowWindow(hwnd, nCmdShow);
130 UpdateWindow(hwnd);
131 
132 MAS::Dialog *dlg = new MyWindow;
133 dlg->ClearFlag(D_MOVABLE | D_RESIZABLE);
134 dlg->Popup();
135 delete dlg;
136 MAS::ExitMASkinG();
137 
138 return msg.wParam;
139}

Notice the WM_NCHITTEST case in the WndProc callback. All you need to do is return HTCAPTION caption on that message when you want to move the window. Also in the MASkinG window I check on every MouseMove if the mouse is over the title bar area and that's all there is to it.

As far as I can see this works, but of course transparent areas in the window (like rounded corners in some skins) are black but I don't think you can fix that easily (let me know if you know how that can be done). Also MASkinG's mouse cursor and the system mouse cursor are not the same. This could probably be fixed by making MASkinG use the hardware cursor...

--
sig used to be here

mail frank
Member #6,213
September 2005

Great! I'll try it.

I've tried your first source code. The window is still a bit flickering. So I modified your code. To notify my application when I detect mouse release. The flickering disapeared but I can only move the window a little bit even I mouse the mouse a lot. Here is my code:

1 
2void CMainDlg::HandleEvent(Widget &obj, int msg, int arg1, int arg2)
3{
4 static int dx = 0;
5 static int dy = 0;
6 
7 Window::HandleEvent(obj, msg, arg1, arg2);
8 
9 if (obj == Window::bGrip || obj == Window::title || obj == Window::textBack)
10 {
11 if (msg == MSG_MOUSEMOVE && (GetMouse()->flags & 1))
12 {
13 dx = arg1;
14 dy = arg2;
15 }
16 }
17 
18 if (msg == MSG_LRELEASE)
19 {
20 if ( dx || dy )
21 {
22 m_pApp->on_size(dx,dy); // this will call win32 api call MoveWindow
23 dx = 0;
24 dy = 0;
25 }
26 }
27}

Are you the one who wrote MASkinG? If yes, I have to say you've done a great job. But I'm very curious is it possible to integrate Openlayer with MASkinG? I tried but failed and I don't have enough time and knowledge to do so.

Anyway I'll try your second code and thank you so much.

miran
Member #2,407
June 2002

Quote:

Are you the one who wrote MASkinG?

Yes. :)

Quote:

If yes, I have to say you've done a great job.

Thank you.

Quote:

But I'm very curious is it possible to integrate Openlayer with MASkinG?

I don't know, I haven't tried. It probably won't be easy even if it is possible, but I am working on making it possible to do that. But you can already use MASkinG with AllegroGL :)

Quote:

Anyway I'll try your second code and thank you so much.

Yeah, the first piece of code I posted doesn't really do much in the right direction. The second piece though works perfectly. And it's only a few lines of code too. :)

--
sig used to be here

mail frank
Member #6,213
September 2005

Thanks for your advice.

You second edition is working perfectly. Now I can move the MASkinG window like a normal appliation without the window's title bar.

I had another question. How can I resize the MASkinG window afterwards? For example, I set the resolution to 160x560, after I press a buttion, the window should become 800x560. If I call resize function of MAS::Window, the window size will be changed but I can only see part of it because the resolution is not changed. But if I call ChangeResolution, the whole window will become black and can't be used any more.

My another option is to open another MAS::Window side by side with the first one after I press the button. I haven't tried this yet. But I don't know whether this is possible.

miran
Member #2,407
June 2002

That's one of the bad things about Allegro. You're stuck with a fixed size window. I think there's a hack to make windows resizable somewhere around though. Search the forums or start a new thread asking "How to make Allegro window resizable" or something...

--
sig used to be here

mail frank
Member #6,213
September 2005

OK. I'll do that. Is it possible to make the DummyDlg's size equal to 0? Or in another word can I at least minimized window?

miran
Member #2,407
June 2002

Minimizing the window is possible of course (through Win32 API I mean). But the MASkinG window doesn't have a minimize icon when it's not resizable (only exit). You could hack the window code to enable the icon (it's there, just disabled) or something...

--
sig used to be here

Go to: