Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wine-mirror
GitHub Repository: wine-mirror/wine
Path: blob/master/programs/explorer/appbar.c
4389 views
1
/*
2
* SHAppBarMessage implementation
3
*
4
* Copyright 2008 Vincent Povirk for CodeWeavers
5
*
6
* This library is free software; you can redistribute it and/or
7
* modify it under the terms of the GNU Lesser General Public
8
* License as published by the Free Software Foundation; either
9
* version 2.1 of the License, or (at your option) any later version.
10
*
11
* This library is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14
* Lesser General Public License for more details.
15
*
16
* You should have received a copy of the GNU Lesser General Public
17
* License along with this library; if not, write to the Free Software
18
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19
*
20
* TODO: freedesktop _NET_WM_STRUT integration
21
*
22
* TODO: find when a fullscreen app is in the foreground and send FULLSCREENAPP
23
* notifications
24
*
25
* TODO: detect changes in the screen size and send ABN_POSCHANGED ?
26
*
27
* TODO: multiple monitor support
28
*/
29
30
#include "windows.h"
31
#include "shellapi.h"
32
#include "wine/debug.h"
33
#include "explorer_private.h"
34
35
#include "wine/list.h"
36
37
WINE_DEFAULT_DEBUG_CHANNEL(appbar);
38
39
struct appbar_data_msg /* platform-independent data */
40
{
41
LONG hWnd;
42
UINT uCallbackMessage;
43
UINT uEdge;
44
RECT rc;
45
ULONGLONG lParam;
46
};
47
48
struct appbar_cmd
49
{
50
ULONG return_map;
51
DWORD return_process;
52
struct appbar_data_msg abd;
53
};
54
55
struct appbar_response
56
{
57
ULONGLONG result;
58
struct appbar_data_msg abd;
59
};
60
61
static HWND appbarmsg_window = NULL;
62
63
struct appbar_data
64
{
65
struct list entry;
66
HWND hwnd;
67
UINT callback_msg;
68
UINT edge;
69
RECT rc;
70
BOOL space_reserved;
71
/* BOOL autohide; */
72
};
73
74
static struct list appbars = LIST_INIT(appbars);
75
76
static struct appbar_data* get_appbar(HWND hwnd)
77
{
78
struct appbar_data* data;
79
80
LIST_FOR_EACH_ENTRY(data, &appbars, struct appbar_data, entry)
81
{
82
if (data->hwnd == hwnd)
83
return data;
84
}
85
86
return NULL;
87
}
88
89
/* send_poschanged: send ABN_POSCHANGED to every appbar except one */
90
static void send_poschanged(HWND hwnd)
91
{
92
struct appbar_data* data;
93
LIST_FOR_EACH_ENTRY(data, &appbars, struct appbar_data, entry)
94
{
95
if (data->hwnd != hwnd)
96
{
97
PostMessageW(data->hwnd, data->callback_msg, ABN_POSCHANGED, 0);
98
}
99
}
100
}
101
102
/* appbar_cliprect: cut out parts of the rectangle that interfere with existing appbars */
103
static void appbar_cliprect( HWND hwnd, RECT *rect )
104
{
105
struct appbar_data* data;
106
LIST_FOR_EACH_ENTRY(data, &appbars, struct appbar_data, entry)
107
{
108
if (data->hwnd == hwnd)
109
{
110
/* we only care about appbars that were added before this one */
111
return;
112
}
113
if (data->space_reserved)
114
{
115
/* move in the side that corresponds to the other appbar's edge */
116
switch (data->edge)
117
{
118
case ABE_BOTTOM:
119
rect->bottom = min(rect->bottom, data->rc.top);
120
break;
121
case ABE_LEFT:
122
rect->left = max(rect->left, data->rc.right);
123
break;
124
case ABE_RIGHT:
125
rect->right = min(rect->right, data->rc.left);
126
break;
127
case ABE_TOP:
128
rect->top = max(rect->top, data->rc.bottom);
129
break;
130
}
131
}
132
}
133
}
134
135
static UINT_PTR handle_appbarmessage(DWORD msg, struct appbar_data_msg *abd)
136
{
137
struct appbar_data* data;
138
HWND hwnd = LongToHandle( abd->hWnd );
139
140
switch (msg)
141
{
142
case ABM_NEW:
143
if (get_appbar(hwnd))
144
{
145
/* fail when adding an hwnd the second time */
146
return FALSE;
147
}
148
149
data = calloc( 1, sizeof(struct appbar_data) );
150
if (!data)
151
{
152
ERR( "out of memory\n" );
153
return FALSE;
154
}
155
data->hwnd = hwnd;
156
data->callback_msg = abd->uCallbackMessage;
157
158
list_add_tail(&appbars, &data->entry);
159
160
return TRUE;
161
case ABM_REMOVE:
162
if ((data = get_appbar(hwnd)))
163
{
164
list_remove(&data->entry);
165
166
send_poschanged(hwnd);
167
168
free( data );
169
}
170
else WARN( "removing hwnd %p not on the list\n", hwnd );
171
return TRUE;
172
case ABM_QUERYPOS:
173
if (abd->uEdge > ABE_BOTTOM) WARN( "invalid edge %i for %p\n", abd->uEdge, hwnd );
174
appbar_cliprect( hwnd, &abd->rc );
175
return TRUE;
176
case ABM_SETPOS:
177
if (abd->uEdge > ABE_BOTTOM)
178
{
179
WARN( "invalid edge %i for %p\n", abd->uEdge, hwnd );
180
return TRUE;
181
}
182
if ((data = get_appbar(hwnd)))
183
{
184
/* calculate acceptable space */
185
appbar_cliprect( hwnd, &abd->rc );
186
187
if (!EqualRect(&abd->rc, &data->rc))
188
send_poschanged(hwnd);
189
190
/* reserve that space for this appbar */
191
data->edge = abd->uEdge;
192
data->rc = abd->rc;
193
data->space_reserved = TRUE;
194
}
195
else
196
{
197
WARN( "app sent ABM_SETPOS message for %p without ABM_ADD\n", hwnd );
198
}
199
return TRUE;
200
case ABM_GETSTATE:
201
FIXME( "SHAppBarMessage(ABM_GETSTATE): stub\n" );
202
return ABS_ALWAYSONTOP | ABS_AUTOHIDE;
203
case ABM_GETTASKBARPOS:
204
FIXME( "SHAppBarMessage(ABM_GETTASKBARPOS, hwnd=%p): stub\n", hwnd );
205
/* Report the taskbar is at the bottom of the screen. */
206
abd->rc.left = 0;
207
abd->rc.right = GetSystemMetrics(SM_CXSCREEN);
208
abd->rc.bottom = GetSystemMetrics(SM_CYSCREEN);
209
abd->rc.top = abd->rc.bottom-1;
210
abd->uEdge = ABE_BOTTOM;
211
return TRUE;
212
case ABM_ACTIVATE:
213
return TRUE;
214
case ABM_GETAUTOHIDEBAR:
215
FIXME( "SHAppBarMessage(ABM_GETAUTOHIDEBAR, hwnd=%p, edge=%x): stub\n", hwnd, abd->uEdge );
216
return 0;
217
case ABM_SETAUTOHIDEBAR:
218
FIXME( "SHAppBarMessage(ABM_SETAUTOHIDEBAR, hwnd=%p, edge=%x, lparam=%s): stub\n", hwnd,
219
abd->uEdge, wine_dbgstr_longlong( abd->lParam ) );
220
return TRUE;
221
case ABM_WINDOWPOSCHANGED:
222
return TRUE;
223
default:
224
FIXME( "SHAppBarMessage(%lx) unimplemented\n", msg );
225
return FALSE;
226
}
227
}
228
229
static LRESULT CALLBACK appbar_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
230
{
231
switch (msg)
232
{
233
case WM_COPYDATA:
234
{
235
COPYDATASTRUCT* cds;
236
struct appbar_cmd cmd;
237
UINT_PTR result;
238
HANDLE return_hproc;
239
HANDLE return_map;
240
LPVOID return_view;
241
struct appbar_response* response;
242
243
cds = (COPYDATASTRUCT*)lparam;
244
if (cds->cbData != sizeof(struct appbar_cmd))
245
return TRUE;
246
CopyMemory(&cmd, cds->lpData, cds->cbData);
247
248
result = handle_appbarmessage(cds->dwData, &cmd.abd);
249
250
return_hproc = OpenProcess(PROCESS_DUP_HANDLE, FALSE, cmd.return_process);
251
if (return_hproc == NULL)
252
{
253
ERR( "couldn't open calling process\n" );
254
return TRUE;
255
}
256
257
if (!DuplicateHandle(return_hproc, UlongToHandle(cmd.return_map),
258
GetCurrentProcess(), &return_map, 0, FALSE, DUPLICATE_SAME_ACCESS))
259
{
260
ERR( "couldn't duplicate handle\n" );
261
CloseHandle(return_hproc);
262
return TRUE;
263
}
264
CloseHandle(return_hproc);
265
266
return_view = MapViewOfFile(return_map, FILE_MAP_WRITE, 0, 0, sizeof(struct appbar_response));
267
268
if (return_view)
269
{
270
response = (struct appbar_response*)return_view;
271
response->result = result;
272
response->abd = cmd.abd;
273
274
UnmapViewOfFile(return_view);
275
}
276
else ERR( "couldn't map view of file\n" );
277
278
CloseHandle(return_map);
279
return TRUE;
280
}
281
default:
282
break;
283
}
284
285
return DefWindowProcW(hwnd, msg, wparam, lparam);
286
}
287
288
void initialize_appbar(void)
289
{
290
WNDCLASSEXW class;
291
292
/* register the appbar window class */
293
ZeroMemory(&class, sizeof(class));
294
class.cbSize = sizeof(class);
295
class.lpfnWndProc = appbar_wndproc;
296
class.hInstance = NULL;
297
class.lpszClassName = L"WineAppBar";
298
299
if (!RegisterClassExW(&class))
300
{
301
ERR( "Could not register appbar message window class\n" );
302
return;
303
}
304
305
appbarmsg_window = CreateWindowW(class.lpszClassName, class.lpszClassName, 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, NULL);
306
if (!appbarmsg_window)
307
{
308
ERR( "Could not create appbar message window\n" );
309
return;
310
}
311
}
312
313