File: appbar.c

package info (click to toggle)
wine 5.0.3-3
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 220,300 kB
  • sloc: ansic: 3,035,623; perl: 19,098; yacc: 16,358; makefile: 10,088; javascript: 9,150; objc: 6,590; lex: 5,734; python: 1,914; cpp: 1,042; sh: 759; java: 749; xml: 557; awk: 69; cs: 17
file content (315 lines) | stat: -rw-r--r-- 9,088 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
/*
 * SHAppBarMessage implementation
 *
 * Copyright 2008 Vincent Povirk for CodeWeavers
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 *
 * TODO: freedesktop _NET_WM_STRUT integration
 *
 * TODO: find when a fullscreen app is in the foreground and send FULLSCREENAPP
 *  notifications
 *
 * TODO: detect changes in the screen size and send ABN_POSCHANGED ?
 *
 * TODO: multiple monitor support
 */

#include "windows.h"
#include "shellapi.h"
#include "wine/debug.h"
#include "explorer_private.h"

#include "wine/list.h"

WINE_DEFAULT_DEBUG_CHANNEL(appbar);

struct appbar_data_msg  /* platform-independent data */
{
    LONG      hWnd;
    UINT      uCallbackMessage;
    UINT      uEdge;
    RECT      rc;
    ULONGLONG lParam;
};

struct appbar_cmd
{
    ULONG  return_map;
    DWORD  return_process;
    struct appbar_data_msg abd;
};

struct appbar_response
{
    ULONGLONG result;
    struct appbar_data_msg abd;
};

static HWND appbarmsg_window = NULL;

struct appbar_data
{
    struct list entry;
    HWND hwnd;
    UINT callback_msg;
    UINT edge;
    RECT rc;
    BOOL space_reserved;
    /* BOOL autohide; */
};

static struct list appbars = LIST_INIT(appbars);

static struct appbar_data* get_appbar(HWND hwnd)
{
    struct appbar_data* data;

    LIST_FOR_EACH_ENTRY(data, &appbars, struct appbar_data, entry)
    {
        if (data->hwnd == hwnd)
            return data;
    }

    return NULL;
}

/* send_poschanged: send ABN_POSCHANGED to every appbar except one */
static void send_poschanged(HWND hwnd)
{
    struct appbar_data* data;
    LIST_FOR_EACH_ENTRY(data, &appbars, struct appbar_data, entry)
    {
        if (data->hwnd != hwnd)
        {
            PostMessageW(data->hwnd, data->callback_msg, ABN_POSCHANGED, 0);
        }
    }
}

/* appbar_cliprect: cut out parts of the rectangle that interfere with existing appbars */
static void appbar_cliprect( HWND hwnd, RECT *rect )
{
    struct appbar_data* data;
    LIST_FOR_EACH_ENTRY(data, &appbars, struct appbar_data, entry)
    {
        if (data->hwnd == hwnd)
        {
            /* we only care about appbars that were added before this one */
            return;
        }
        if (data->space_reserved)
        {
            /* move in the side that corresponds to the other appbar's edge */
            switch (data->edge)
            {
            case ABE_BOTTOM:
                rect->bottom = min(rect->bottom, data->rc.top);
                break;
            case ABE_LEFT:
                rect->left = max(rect->left, data->rc.right);
                break;
            case ABE_RIGHT:
                rect->right = min(rect->right, data->rc.left);
                break;
            case ABE_TOP:
                rect->top = max(rect->top, data->rc.bottom);
                break;
            }
        }
    }
}

static UINT_PTR handle_appbarmessage(DWORD msg, struct appbar_data_msg *abd)
{
    struct appbar_data* data;
    HWND hwnd = LongToHandle( abd->hWnd );

    switch (msg)
    {
    case ABM_NEW:
        if (get_appbar(hwnd))
        {
            /* fail when adding an hwnd the second time */
            return FALSE;
        }

        data = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct appbar_data));
        if (!data)
        {
            WINE_ERR("out of memory\n");
            return FALSE;
        }
        data->hwnd = hwnd;
        data->callback_msg = abd->uCallbackMessage;

        list_add_tail(&appbars, &data->entry);

        return TRUE;
    case ABM_REMOVE:
        if ((data = get_appbar(hwnd)))
        {
            list_remove(&data->entry);

            send_poschanged(hwnd);

            HeapFree(GetProcessHeap(), 0, data);
        }
        else
            WINE_WARN("removing hwnd %p not on the list\n", hwnd);
        return TRUE;
    case ABM_QUERYPOS:
        if (abd->uEdge > ABE_BOTTOM)
            WINE_WARN("invalid edge %i for %p\n", abd->uEdge, hwnd);
        appbar_cliprect( hwnd, &abd->rc );
        return TRUE;
    case ABM_SETPOS:
        if (abd->uEdge > ABE_BOTTOM)
        {
            WINE_WARN("invalid edge %i for %p\n", abd->uEdge, hwnd);
            return TRUE;
        }
        if ((data = get_appbar(hwnd)))
        {
            /* calculate acceptable space */
            appbar_cliprect( hwnd, &abd->rc );

            if (!EqualRect(&abd->rc, &data->rc))
                send_poschanged(hwnd);

            /* reserve that space for this appbar */
            data->edge = abd->uEdge;
            data->rc = abd->rc;
            data->space_reserved = TRUE;
        }
        else
        {
            WINE_WARN("app sent ABM_SETPOS message for %p without ABM_ADD\n", hwnd);
        }
        return TRUE;
    case ABM_GETSTATE:
        WINE_FIXME("SHAppBarMessage(ABM_GETSTATE): stub\n");
        return ABS_ALWAYSONTOP | ABS_AUTOHIDE;
    case ABM_GETTASKBARPOS:
        WINE_FIXME("SHAppBarMessage(ABM_GETTASKBARPOS, hwnd=%p): stub\n", hwnd);
        /* Report the taskbar is at the bottom of the screen. */
        abd->rc.left = 0;
        abd->rc.right = GetSystemMetrics(SM_CXSCREEN);
        abd->rc.bottom = GetSystemMetrics(SM_CYSCREEN);
        abd->rc.top = abd->rc.bottom-1;
        abd->uEdge = ABE_BOTTOM;
        return TRUE;
    case ABM_ACTIVATE:
        return TRUE;
    case ABM_GETAUTOHIDEBAR:
        WINE_FIXME("SHAppBarMessage(ABM_GETAUTOHIDEBAR, hwnd=%p, edge=%x): stub\n", hwnd, abd->uEdge);
        return 0;
    case ABM_SETAUTOHIDEBAR:
        WINE_FIXME("SHAppBarMessage(ABM_SETAUTOHIDEBAR, hwnd=%p, edge=%x, lparam=%s): stub\n",
                   hwnd, abd->uEdge, wine_dbgstr_longlong(abd->lParam));
        return TRUE;
    case ABM_WINDOWPOSCHANGED:
        return TRUE;
    default:
        WINE_FIXME("SHAppBarMessage(%x) unimplemented\n", msg);
        return FALSE;
    }
}

static LRESULT CALLBACK appbar_wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
    switch (msg)
    {
    case WM_COPYDATA:
        {
            COPYDATASTRUCT* cds;
            struct appbar_cmd cmd;
            UINT_PTR result;
            HANDLE return_hproc;
            HANDLE return_map;
            LPVOID return_view;
            struct appbar_response* response;

            cds = (COPYDATASTRUCT*)lparam;
            if (cds->cbData != sizeof(struct appbar_cmd))
                return TRUE;
            CopyMemory(&cmd, cds->lpData, cds->cbData);

            result = handle_appbarmessage(cds->dwData, &cmd.abd);

            return_hproc = OpenProcess(PROCESS_DUP_HANDLE, FALSE, cmd.return_process);
            if (return_hproc == NULL)
            {
                WINE_ERR("couldn't open calling process\n");
                return TRUE;
            }

            if (!DuplicateHandle(return_hproc, UlongToHandle(cmd.return_map),
                                 GetCurrentProcess(), &return_map, 0, FALSE, DUPLICATE_SAME_ACCESS))
            {
                WINE_ERR("couldn't duplicate handle\n");
                CloseHandle(return_hproc);
                return TRUE;
            }
            CloseHandle(return_hproc);

            return_view = MapViewOfFile(return_map, FILE_MAP_WRITE, 0, 0, sizeof(struct appbar_response));

            if (return_view)
            {
                response = (struct appbar_response*)return_view;
                response->result = result;
                response->abd = cmd.abd;

                UnmapViewOfFile(return_view);
            }
            else
                WINE_ERR("couldn't map view of file\n");

            CloseHandle(return_map);
            return TRUE;
        }
    default:
        break;
    }

    return DefWindowProcW(hwnd, msg, wparam, lparam);
}

void initialize_appbar(void)
{
    WNDCLASSEXW class;
    static const WCHAR classname[] = {'W','i','n','e','A','p','p','B','a','r',0};

    /* register the appbar window class */
    ZeroMemory(&class, sizeof(class));
    class.cbSize = sizeof(class);
    class.lpfnWndProc = appbar_wndproc;
    class.hInstance = NULL;
    class.lpszClassName = classname;

    if (!RegisterClassExW(&class))
    {
        WINE_ERR("Could not register appbar message window class\n");
        return;
    }

    appbarmsg_window = CreateWindowW(classname, classname, 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, NULL);
    if (!appbarmsg_window)
    {
        WINE_ERR("Could not create appbar message window\n");
        return;
    }
}