1fcb006dcSAxel Dörfler/*
2954a0a0cSStephan Aßmus * Copyright 2001-2019, Haiku.
3fcb006dcSAxel Dörfler * Distributed under the terms of the MIT License.
4fcb006dcSAxel Dörfler *
5fcb006dcSAxel Dörfler * Authors:
6fcb006dcSAxel Dörfler *		DarkWyrm <bpmagic@columbus.rr.com>
72c8cfe2dSAdi Oanca *		Adrian Oanca <adioanca@gmail.com>
8fcb006dcSAxel Dörfler *		Stephan A��mus <superstippi@gmx.de>
93e20b062SStefano Ceccherini *		Stefano Ceccherini <stefano.ceccherini@gmail.com>
10926e63c8SBrecht Machiels *		Axel D��rfler <axeld@pinc-software.de>
11431dc47dSStephan Aßmus *		Artur Wyszynski <harakash@gmail.com>
12926e63c8SBrecht Machiels *		Philippe Saint-Pierre <stpere@gmail.com>
13926e63c8SBrecht Machiels *		Brecht Machiels <brecht@mos6581.org>
14551438b9SJulian Harnath *		Julian Harnath <julian.harnath@rwth-aachen.de>
157f9368caSlooncraz *		Joseph Groover <looncraz@looncraz.net>
16fcb006dcSAxel Dörfler */
17fcb006dcSAxel Dörfler
18c6a25272SAxel Dörfler
1907e13b5fSAxel Dörfler/*!	\class ServerWindow
2007e13b5fSAxel Dörfler
2107e13b5fSAxel Dörfler	The ServerWindow class handles all BWindow messaging; it forwards all
2207e13b5fSAxel Dörfler	BWindow requests to the corresponding app_server classes, that is Desktop,
2307e13b5fSAxel Dörfler	Window, and View.
2407e13b5fSAxel Dörfler	Furthermore, it also sends app_server requests/notices to its BWindow. There
2507e13b5fSAxel Dörfler	is one ServerWindow per BWindow.
26c6a25272SAxel Dörfler*/
27c6a25272SAxel Dörfler
28f598d348SAxel Dörfler
290ac013e6SAxel Dörfler#include "ServerWindow.h"
304ceb1e51SAxel Dörfler
3107e13b5fSAxel Dörfler#include <syslog.h>
3207e13b5fSAxel Dörfler#include <new>
3307e13b5fSAxel Dörfler
3407e13b5fSAxel Dörfler#include <AppDefs.h>
3507e13b5fSAxel Dörfler#include <Autolock.h>
3607e13b5fSAxel Dörfler#include <Debug.h>
3707e13b5fSAxel Dörfler#include <DirectWindow.h>
3807e13b5fSAxel Dörfler#include <TokenSpace.h>
3907e13b5fSAxel Dörfler#include <View.h>
4007e13b5fSAxel Dörfler#include <GradientLinear.h>
4107e13b5fSAxel Dörfler#include <GradientRadial.h>
4207e13b5fSAxel Dörfler#include <GradientRadialFocus.h>
4307e13b5fSAxel Dörfler#include <GradientDiamond.h>
4407e13b5fSAxel Dörfler#include <GradientConic.h>
4507e13b5fSAxel Dörfler
4607e13b5fSAxel Dörfler#include <MessagePrivate.h>
4707e13b5fSAxel Dörfler#include <PortLink.h>
484bd6f322SJulian Harnath#include <ShapePrivate.h>
4907e13b5fSAxel Dörfler#include <ServerProtocolStructs.h>
5007e13b5fSAxel Dörfler#include <ViewPrivate.h>
5107e13b5fSAxel Dörfler#include <WindowInfo.h>
5207e13b5fSAxel Dörfler#include <WindowPrivate.h>
5307e13b5fSAxel Dörfler
5407e13b5fSAxel Dörfler#include "clipping.h"
5577e5acc0SStephan Aßmus#include "utf8_functions.h"
5607e13b5fSAxel Dörfler
57215119a1SStephan Aßmus#include "AlphaMask.h"
5870acf9f9SDarkWyrm#include "AppServer.h"
5977e5acc0SStephan Aßmus#include "AutoDeleter.h"
60e0d1cc18SAdrien Destugues#include "BBitmapBuffer.h"
61e0d1cc18SAdrien Destugues#include "BitmapManager.h"
6237aec728SDarkWyrm#include "Desktop.h"
63a5a64d54SAxel Dörfler#include "DirectWindowInfo.h"
646ed89418SStephan Aßmus#include "DrawingEngine.h"
65bd06a41cSClemens Zeidler#include "DrawState.h"
663dcb3b07SStephan Aßmus#include "HWInterface.h"
67551438b9SJulian Harnath#include "Layer.h"
680ac013e6SAxel Dörfler#include "Overlay.h"
6967f3be42SStephan Aßmus#include "ProfileMessageSupport.h"
701fbd158eSStefano Ceccherini#include "RenderingBuffer.h"
7170acf9f9SDarkWyrm#include "ServerApp.h"
723dcb3b07SStephan Aßmus#include "ServerBitmap.h"
7345ca1c94SStefano Ceccherini#include "ServerPicture.h"
743dcb3b07SStephan Aßmus#include "ServerProtocol.h"
75953d895eSAxel Dörfler#include "Window.h"
76953d895eSAxel Dörfler#include "WorkspacesView.h"
773dcb3b07SStephan Aßmus
780ac013e6SAxel Dörfler
79758b1d0eSIngo Weinholdusing std::nothrow;
80758b1d0eSIngo Weinhold
8107e13b5fSAxel Dörfler
82a631158aSAxel Dörfler//#define TRACE_SERVER_WINDOW
83a631158aSAxel Dörfler#ifdef TRACE_SERVER_WINDOW
8492e26ba9SAdi Oanca#	include <stdio.h>
85e98ee141SStephan Aßmus#	define STRACE(x) debug_printf x
8692e26ba9SAdi Oanca#else
8792e26ba9SAdi Oanca#	define STRACE(x) ;
8892e26ba9SAdi Oanca#endif
8992e26ba9SAdi Oanca
90e98ee141SStephan Aßmus//#define TRACE_SERVER_WINDOW_MESSAGES
91a631158aSAxel Dörfler#ifdef TRACE_SERVER_WINDOW_MESSAGES
920d9d87e7SDarkWyrm#	include <stdio.h>
93e98ee141SStephan Aßmusstatic const char* kDrawingModeMap[] = {
94e98ee141SStephan Aßmus	"B_OP_COPY",
95e98ee141SStephan Aßmus	"B_OP_OVER",
96e98ee141SStephan Aßmus	"B_OP_ERASE",
97e98ee141SStephan Aßmus	"B_OP_INVERT",
98e98ee141SStephan Aßmus	"B_OP_ADD",
99e98ee141SStephan Aßmus	"B_OP_SUBTRACT",
100e98ee141SStephan Aßmus	"B_OP_BLEND",
101e98ee141SStephan Aßmus	"B_OP_MIN",
102e98ee141SStephan Aßmus	"B_OP_MAX",
103e98ee141SStephan Aßmus	"B_OP_SELECT",
104e98ee141SStephan Aßmus	"B_OP_ALPHA",
105e98ee141SStephan Aßmus
106e98ee141SStephan Aßmus	"fix kDrawingModeMap",
107e98ee141SStephan Aßmus	"fix kDrawingModeMap",
108e98ee141SStephan Aßmus	"fix kDrawingModeMap",
109e98ee141SStephan Aßmus	"fix kDrawingModeMap",
110e98ee141SStephan Aßmus	"fix kDrawingModeMap",
111e98ee141SStephan Aßmus};
112e98ee141SStephan Aßmus#	define DTRACE(x) debug_printf x
1130d9d87e7SDarkWyrm#else
1140d9d87e7SDarkWyrm#	define DTRACE(x) ;
1150d9d87e7SDarkWyrm#endif
1160d9d87e7SDarkWyrm
117e98ee141SStephan Aßmus//#define TRACE_SERVER_GRADIENTS
118991547efSStephan Aßmus#ifdef TRACE_SERVER_GRADIENTS
119991547efSStephan Aßmus#	include <OS.h>
120991547efSStephan Aßmus#	define GTRACE(x) debug_printf x
121991547efSStephan Aßmus#else
122991547efSStephan Aßmus#	define GTRACE(x) ;
123991547efSStephan Aßmus#endif
124991547efSStephan Aßmus
125e98ee141SStephan Aßmus//#define PROFILE_MESSAGE_LOOP
126fa2c53edSAxel Dörfler#ifdef PROFILE_MESSAGE_LOOP
12767f3be42SStephan Aßmusstruct profile { int32 code; int32 count; bigtime_t time; };
12867f3be42SStephan Aßmusstatic profile sMessageProfile[AS_LAST_CODE];
12967f3be42SStephan Aßmusstatic profile sRedrawProcessingTime;
13067f3be42SStephan Aßmus//static profile sNextMessageTime;
131fa2c53edSAxel Dörfler#endif
132fa2c53edSAxel Dörfler
133bff84e78SAxel Dörfler
1340eed9183SAxel Dörfler//	#pragma mark -
1350eed9183SAxel Dörfler
1360eed9183SAxel Dörfler
1370eed9183SAxel Dörfler#ifdef PROFILE_MESSAGE_LOOP
1380eed9183SAxel Dörflerstatic int
1390eed9183SAxel Dörflercompare_message_profiles(const void* _a, const void* _b)
1400eed9183SAxel Dörfler{
1410eed9183SAxel Dörfler	profile* a = (profile*)*(void**)_a;
1420eed9183SAxel Dörfler	profile* b = (profile*)*(void**)_b;
1430eed9183SAxel Dörfler	if (a->time < b->time)
1440eed9183SAxel Dörfler		return 1;
1450eed9183SAxel Dörfler	if (a->time > b->time)
1460eed9183SAxel Dörfler		return -1;
1470eed9183SAxel Dörfler	return 0;
1480eed9183SAxel Dörfler}
1490eed9183SAxel Dörfler#endif
1500eed9183SAxel Dörfler
1510eed9183SAxel Dörfler
152bff84e78SAxel Dörfler//	#pragma mark -
153bff84e78SAxel Dörfler
154bff84e78SAxel Dörfler
15507e13b5fSAxel Dörfler/*!	Sets up the basic BWindow counterpart - you have to call Init() before
1564b813bf2SAxel Dörfler	you can actually use it, though.
1576e4bef60SDarkWyrm*/
1580eed9183SAxel DörflerServerWindow::ServerWindow(const char* title, ServerApp* app,
1590eed9183SAxel Dörfler		port_id clientPort, port_id looperPort, int32 clientToken)
1600eed9183SAxel Dörfler	:
1610eed9183SAxel Dörfler	MessageLooper(title && *title ? title : "Unnamed Window"),
162dfd5b499SAxel Dörfler	fTitle(NULL),
163959a5a68SAxel Dörfler	fDesktop(app->GetDesktop()),
164fcb006dcSAxel Dörfler	fServerApp(app),
165953d895eSAxel Dörfler	fWindow(NULL),
1663a44e6e3SAxel Dörfler	fWindowAddedToDesktop(false),
167e83820edSAxel Dörfler
168ce1639b2SAxel Dörfler	fClientTeam(app->ClientTeam()),
169e83820edSAxel Dörfler
170ce1639b2SAxel Dörfler	fMessagePort(-1),
171fcb006dcSAxel Dörfler	fClientReplyPort(clientPort),
172d7c2c050SAdi Oanca	fClientLooperPort(looperPort),
173e83820edSAxel Dörfler
174d9525baaSAxel Dörfler	fClientToken(clientToken),
175e83820edSAxel Dörfler
176953d895eSAxel Dörfler	fCurrentView(NULL),
177e83820edSAxel Dörfler	fCurrentDrawingRegion(),
178e83820edSAxel Dörfler	fCurrentDrawingRegionValid(false),
179e83820edSAxel Dörfler
180a5a64d54SAxel Dörfler	fDirectWindowInfo(NULL),
181a5a64d54SAxel Dörfler	fIsDirectlyAccessing(false)
18270acf9f9SDarkWyrm{
183a38e46a0SAxel Dörfler	STRACE(("ServerWindow(%s)::ServerWindow()\n", title));
1846a0a0a80SAxel Dörfler
185dfd5b499SAxel Dörfler	SetTitle(title);
1866a0a0a80SAxel Dörfler	fServerToken = BPrivate::gDefaultTokens.NewToken(B_SERVER_TOKEN, this);
187f6859878SAxel Dörfler
1884ceb1e51SAxel Dörfler	BMessenger::Private(fFocusMessenger).SetTo(fClientTeam,
1894ceb1e51SAxel Dörfler		looperPort, B_PREFERRED_TOKEN);
1904ceb1e51SAxel Dörfler	BMessenger::Private(fHandlerMessenger).SetTo(fClientTeam,
1914ceb1e51SAxel Dörfler		looperPort, clientToken);
19267e79bf4SAxel Dörfler
193f89b4c9aSAxel Dörfler	fEventTarget.SetTo(fFocusMessenger);
194f89b4c9aSAxel Dörfler
19567e79bf4SAxel Dörfler	fDeathSemaphore = create_sem(0, "window death");
19670acf9f9SDarkWyrm}
197280d1aacSAxel Dörfler
19854f92239SAxel Dörfler
19907e13b5fSAxel Dörfler/*! Tears down all connections the main app_server objects, and deletes some
20007e13b5fSAxel Dörfler	internals.
20107e13b5fSAxel Dörfler*/
202ce1639b2SAxel DörflerServerWindow::~ServerWindow()
20370acf9f9SDarkWyrm{
204a631158aSAxel Dörfler	STRACE(("ServerWindow(%s@%p):~ServerWindow()\n", fTitle, this));
205e438905aSAdi Oanca
206953d895eSAxel Dörfler	if (!fWindow->IsOffscreenWindow()) {
2073a44e6e3SAxel Dörfler		fWindowAddedToDesktop = false;
208953d895eSAxel Dörfler		fDesktop->RemoveWindow(fWindow);
2093a44e6e3SAxel Dörfler	}
210806767ecSAxel Dörfler
211edb62548SMichael Lotz	if (App() != NULL) {
212f33610f8SAxel Dörfler		App()->RemoveWindow(this);
213edb62548SMichael Lotz		fServerApp = NULL;
214edb62548SMichael Lotz	}
215f33610f8SAxel Dörfler
216953d895eSAxel Dörfler	delete fWindow;
2173a44e6e3SAxel Dörfler
218dfd5b499SAxel Dörfler	free(fTitle);
219806767ecSAxel Dörfler	delete_port(fMessagePort);
220e438905aSAdi Oanca
2216a0a0a80SAxel Dörfler	BPrivate::gDefaultTokens.RemoveToken(fServerToken);
2226a0a0a80SAxel Dörfler
223a5a64d54SAxel Dörfler	delete fDirectWindowInfo;
224a631158aSAxel Dörfler	STRACE(("ServerWindow(%p) will exit NOW\n", this));
22567e79bf4SAxel Dörfler
22667e79bf4SAxel Dörfler	delete_sem(fDeathSemaphore);
227fa2c53edSAxel Dörfler
228fa2c53edSAxel Dörfler#ifdef PROFILE_MESSAGE_LOOP
22967f3be42SStephan Aßmus	BList profiles;
230fa2c53edSAxel Dörfler	for (int32 i = 0; i < AS_LAST_CODE; i++) {
231fa2c53edSAxel Dörfler		if (sMessageProfile[i].count == 0)
232fa2c53edSAxel Dörfler			continue;
23367f3be42SStephan Aßmus		sMessageProfile[i].code = i;
23467f3be42SStephan Aßmus		profiles.AddItem(&sMessageProfile[i]);
235fa2c53edSAxel Dörfler	}
23667f3be42SStephan Aßmus
23767f3be42SStephan Aßmus	profiles.SortItems(compare_message_profiles);
23867f3be42SStephan Aßmus
23967f3be42SStephan Aßmus	int32 count = profiles.CountItems();
24067f3be42SStephan Aßmus	for (int32 i = 0; i < count; i++) {
24167f3be42SStephan Aßmus		profile* p = (profile*)profiles.ItemAtFast(i);
2423fed1a15SAlex Smith		printf("[%s] called %" B_PRId32 " times, %g secs (%" B_PRId64 " usecs "
243cc7e3a05SAdrien Destugues			"per call)\n", string_for_message_code(p->code), p->count, p->time / 1000000.0,
24467f3be42SStephan Aßmus			p->time / p->count);
24567f3be42SStephan Aßmus	}
24667f3be42SStephan Aßmus	if (sRedrawProcessingTime.count > 0) {
2473fed1a15SAlex Smith		printf("average redraw processing time: %g secs, count: %" B_PRId32 " "
2483fed1a15SAlex Smith			"(%" B_PRId64 " usecs per call)\n",
2493fed1a15SAlex Smith			sRedrawProcessingTime.time / 1000000.0, sRedrawProcessingTime.count,
25067f3be42SStephan Aßmus			sRedrawProcessingTime.time / sRedrawProcessingTime.count);
25167f3be42SStephan Aßmus	}
25267f3be42SStephan Aßmus//	if (sNextMessageTime.count > 0) {
25367f3be42SStephan Aßmus//		printf("average NextMessage() time: %g secs, count: %ld (%lld usecs per call)\n",
25467f3be42SStephan Aßmus//			sNextMessageTime.time / 1000000.0, sNextMessageTime.count,
25567f3be42SStephan Aßmus//			sNextMessageTime.time / sNextMessageTime.count);
25667f3be42SStephan Aßmus//	}
257fa2c53edSAxel Dörfler#endif
25870acf9f9SDarkWyrm}
259a596e677SDarkWyrm
260ce1639b2SAxel Dörfler
261ce1639b2SAxel Dörflerstatus_t
26285096c8aSAxel DörflerServerWindow::Init(BRect frame, window_look look, window_feel feel,
26385096c8aSAxel Dörfler	uint32 flags, uint32 workspace)
264ce1639b2SAxel Dörfler{
265f33610f8SAxel Dörfler	if (!App()->AddWindow(this)) {
266f33610f8SAxel Dörfler		fServerApp = NULL;
267f33610f8SAxel Dörfler		return B_NO_MEMORY;
268f33610f8SAxel Dörfler	}
269f33610f8SAxel Dörfler
270094efed4SMarcus Overhagen	if (fTitle == NULL)
271094efed4SMarcus Overhagen		return B_NO_MEMORY;
272094efed4SMarcus Overhagen
273359c905cSStephan Aßmus	// fMessagePort is the port to which the app sends messages for the server
274359c905cSStephan Aßmus	fMessagePort = create_port(100, fTitle);
275ce1639b2SAxel Dörfler	if (fMessagePort < B_OK)
276ce1639b2SAxel Dörfler		return fMessagePort;
277ce1639b2SAxel Dörfler
278359c905cSStephan Aßmus	fLink.SetSenderPort(fClientReplyPort);
279359c905cSStephan Aßmus	fLink.SetReceiverPort(fMessagePort);
280359c905cSStephan Aßmus
281953d895eSAxel Dörfler	// We cannot call MakeWindow in the constructor, since it
282cf434f8eSStephan Aßmus	// is a virtual function!
283953d895eSAxel Dörfler	fWindow = MakeWindow(frame, fTitle, look, feel, flags, workspace);
284582b3d5aSStephan Aßmus	if (!fWindow || fWindow->InitCheck() != B_OK) {
285582b3d5aSStephan Aßmus		delete fWindow;
286582b3d5aSStephan Aßmus		fWindow = NULL;
287359c905cSStephan Aßmus		return B_NO_MEMORY;
288582b3d5aSStephan Aßmus	}
289359c905cSStephan Aßmus
290953d895eSAxel Dörfler	if (!fWindow->IsOffscreenWindow()) {
291953d895eSAxel Dörfler		fDesktop->AddWindow(fWindow);
2923a44e6e3SAxel Dörfler		fWindowAddedToDesktop = true;
2933a44e6e3SAxel Dörfler	}
294359c905cSStephan Aßmus
295ce1639b2SAxel Dörfler	return B_OK;
296ce1639b2SAxel Dörfler}
297ce1639b2SAxel Dörfler
298ce1639b2SAxel Dörfler
299fe9c291bSAxel Dörfler/*!	Returns the ServerWindow's Window, if it exists and has been
300fe9c291bSAxel Dörfler	added to the Desktop already.
301fe9c291bSAxel Dörfler	In other words, you cannot assume this method will always give you
302fe9c291bSAxel Dörfler	a valid pointer.
303fe9c291bSAxel Dörfler*/
304fe9c291bSAxel DörflerWindow*
305fe9c291bSAxel DörflerServerWindow::Window() const
306fe9c291bSAxel Dörfler{
307fe9c291bSAxel Dörfler	if (!fWindowAddedToDesktop)
308fe9c291bSAxel Dörfler		return NULL;
309fe9c291bSAxel Dörfler
310fe9c291bSAxel Dörfler	return fWindow;
311fe9c291bSAxel Dörfler}
312fe9c291bSAxel Dörfler
313fe9c291bSAxel Dörfler
314280d1aacSAxel Dörflervoid
315c6a25272SAxel DörflerServerWindow::_PrepareQuit()
3166e4bef60SDarkWyrm{
317ce1639b2SAxel Dörfler	if (fThread == find_thread(NULL)) {
318806767ecSAxel Dörfler		// make sure we're hidden
319f8d8085dSAxel Dörfler		fDesktop->LockSingleWindow();
320f8d8085dSAxel Dörfler		_Hide();
321f8d8085dSAxel Dörfler		fDesktop->UnlockSingleWindow();
322c6a25272SAxel Dörfler	} else if (fThread >= B_OK)
32359347b7fSRyan Leavengood		PostMessage(AS_INTERNAL_HIDE_WINDOW);
32470acf9f9SDarkWyrm}
325280d1aacSAxel Dörfler
326ce1639b2SAxel Dörfler
327280d1aacSAxel Dörflervoid
32889ab121eSAxel DörflerServerWindow::_GetLooperName(char* name, size_t length)
32970acf9f9SDarkWyrm{
330dfd5b499SAxel Dörfler	const char *title = Title();
331dfd5b499SAxel Dörfler	if (title == NULL || !title[0])
332dfd5b499SAxel Dörfler		title = "Unnamed Window";
333dfd5b499SAxel Dörfler
3343fed1a15SAlex Smith	snprintf(name, length, "w:%" B_PRId32 ":%s", ClientTeam(), title);
335ce1639b2SAxel Dörfler}
336280d1aacSAxel Dörfler
337ce1639b2SAxel Dörfler
338bf3a2064SStephan Aßmus/*! Shows the window's Window.
33996c6ee95SAxel Dörfler*/
340280d1aacSAxel Dörflervoid
341f8d8085dSAxel DörflerServerWindow::_Show()
34270acf9f9SDarkWyrm{
343ddf57545SAdi Oanca	// NOTE: if you do something else, other than sending a port message, PLEASE lock
344f8d8085dSAxel Dörfler	STRACE(("ServerWindow %s: _Show\n", Title()));
3458491b626SAdi Oanca
3462ea5e5e8SAxel Dörfler	if (fQuitting || fWindow->IsMinimized() || !fWindow->IsHidden()
347121ce643SAxel Dörfler		|| fWindow->IsOffscreenWindow() || fWindow->TopView() == NULL)
348fa554b7dSAdi Oanca		return;
349fa554b7dSAdi Oanca
350bf3a2064SStephan Aßmus	// TODO: Maybe we need to dispatch a message to the desktop to show/hide us
351bf3a2064SStephan Aßmus	// instead of doing it from this thread.
352bf3a2064SStephan Aßmus	fDesktop->UnlockSingleWindow();
353953d895eSAxel Dörfler	fDesktop->ShowWindow(fWindow);
3548ce4644fSStefano Ceccherini	if (fDirectWindowInfo && fDirectWindowInfo->IsFullScreen())
3558ce4644fSStefano Ceccherini		_ResizeToFullScreen();
3566f2a446eSJulian Harnath
357bf3a2064SStephan Aßmus	fDesktop->LockSingleWindow();
35870acf9f9SDarkWyrm}
359280d1aacSAxel Dörfler
36077e79df0SStefano Ceccherini
36196c6ee95SAxel Dörfler/*! Hides the window's Window. You need to have all windows locked when
36296c6ee95SAxel Dörfler	calling this function.
36396c6ee95SAxel Dörfler*/
364280d1aacSAxel Dörflervoid
365f8d8085dSAxel DörflerServerWindow::_Hide()
36670acf9f9SDarkWyrm{
367f8d8085dSAxel Dörfler	STRACE(("ServerWindow %s: _Hide\n", Title()));
3688491b626SAdi Oanca
369953d895eSAxel Dörfler	if (fWindow->IsHidden() || fWindow->IsOffscreenWindow())
370fa554b7dSAdi Oanca		return;
371fa554b7dSAdi Oanca
372bf3a2064SStephan Aßmus	fDesktop->UnlockSingleWindow();
373953d895eSAxel Dörfler	fDesktop->HideWindow(fWindow);
374bf3a2064SStephan Aßmus	fDesktop->LockSingleWindow();
3756e4bef60SDarkWyrm}
376280d1aacSAxel Dörfler
377280d1aacSAxel Dörfler
37858290b7bSAxel Dörflervoid
37958290b7bSAxel DörflerServerWindow::RequestRedraw()
38058290b7bSAxel Dörfler{
38158290b7bSAxel Dörfler	PostMessage(AS_REDRAW, 0);
38258290b7bSAxel Dörfler		// we don't care if this fails - it's only a notification, and if
38358290b7bSAxel Dörfler		// it fails, there are obviously enough messages in the queue
38458290b7bSAxel Dörfler		// already
38558290b7bSAxel Dörfler
38658290b7bSAxel Dörfler	atomic_add(&fRedrawRequested, 1);
38758290b7bSAxel Dörfler}
38858290b7bSAxel Dörfler
38958290b7bSAxel Dörfler
3902b1246d9SAxel Dörflervoid
3912b1246d9SAxel DörflerServerWindow::SetTitle(const char* newTitle)
3922b1246d9SAxel Dörfler{
393dfd5b499SAxel Dörfler	char* oldTitle = fTitle;
394094efed4SMarcus Overhagen
395dfd5b499SAxel Dörfler	if (newTitle == NULL)
396dfd5b499SAxel Dörfler		newTitle = "";
397094efed4SMarcus Overhagen
398dfd5b499SAxel Dörfler	fTitle = strdup(newTitle);
399094efed4SMarcus Overhagen	if (fTitle == NULL) {
400dfd5b499SAxel Dörfler		// out of memory condition
401094efed4SMarcus Overhagen		fTitle = oldTitle;
4022b1246d9SAxel Dörfler		return;
403094efed4SMarcus Overhagen	}
404094efed4SMarcus Overhagen
405dfd5b499SAxel Dörfler	free(oldTitle);
4062b1246d9SAxel Dörfler
4072b1246d9SAxel Dörfler	if (Thread() >= B_OK) {
4082b1246d9SAxel Dörfler		char name[B_OS_NAME_LENGTH];
409dfd5b499SAxel Dörfler		_GetLooperName(name, sizeof(name));
4102b1246d9SAxel Dörfler		rename_thread(Thread(), name);
4112b1246d9SAxel Dörfler	}
4122b1246d9SAxel Dörfler
4135b576468SAxel Dörfler	if (fWindow != NULL)
414953d895eSAxel Dörfler		fDesktop->SetWindowTitle(fWindow, newTitle);
4152b1246d9SAxel Dörfler}
4162b1246d9SAxel Dörfler
4172b1246d9SAxel Dörfler
418ce1639b2SAxel Dörfler//! Requests that the ServerWindow's BWindow quit
419280d1aacSAxel Dörflervoid
420ce1639b2SAxel DörflerServerWindow::NotifyQuitRequested()
421ce1639b2SAxel Dörfler{
4220896fce5SStephan Aßmus	// NOTE: if you do something else, other than sending a port message,
4230896fce5SStephan Aßmus	// PLEASE lock
424ce1639b2SAxel Dörfler	STRACE(("ServerWindow %s: Quit\n", fTitle));
425ce1639b2SAxel Dörfler
426ce1639b2SAxel Dörfler	BMessage msg(B_QUIT_REQUESTED);
427ce1639b2SAxel Dörfler	SendMessageToClient(&msg);
428ce1639b2SAxel Dörfler}
429ce1639b2SAxel Dörfler
430ce1639b2SAxel Dörfler
431ce1639b2SAxel Dörflervoid
432ce1639b2SAxel DörflerServerWindow::NotifyMinimize(bool minimize)
43370e337a0SDarkWyrm{
4345b576468SAxel Dörfler	if (fWindow->Feel() != B_NORMAL_WINDOW_FEEL)
435bfe69873SAxel Dörfler		return;
436bfe69873SAxel Dörfler
437995ab7b3SAxel Dörfler	// The client is responsible for the actual minimization
438280d1aacSAxel Dörfler
439995ab7b3SAxel Dörfler	BMessage msg(B_MINIMIZE);
440995ab7b3SAxel Dörfler	msg.AddInt64("when", real_time_clock_usecs());
441995ab7b3SAxel Dörfler	msg.AddBool("minimize", minimize);
442280d1aacSAxel Dörfler
443995ab7b3SAxel Dörfler	SendMessageToClient(&msg);
4445580db51SAdi Oanca}
445280d1aacSAxel Dörfler
446995ab7b3SAxel Dörfler
447280d1aacSAxel Dörfler//! Sends a message to the client to perform a Zoom
448280d1aacSAxel Dörflervoid
449ce1639b2SAxel DörflerServerWindow::NotifyZoom()
45070e337a0SDarkWyrm{
4510896fce5SStephan Aßmus	// NOTE: if you do something else, other than sending a port message,
4520896fce5SStephan Aßmus	// PLEASE lock
453280d1aacSAxel Dörfler	BMessage msg(B_ZOOM);
454a64bba12SDarkWyrm	SendMessageToClient(&msg);
4555580db51SAdi Oanca}
456280d1aacSAxel Dörfler
4576a0a0a80SAxel Dörfler
4586a0a0a80SAxel Dörflervoid
4596a0a0a80SAxel DörflerServerWindow::GetInfo(window_info& info)
4606a0a0a80SAxel Dörfler{
4616a0a0a80SAxel Dörfler	info.team = ClientTeam();
4626a0a0a80SAxel Dörfler	info.server_token = ServerToken();
4636a0a0a80SAxel Dörfler
4646a0a0a80SAxel Dörfler	info.thread = Thread();
4656a0a0a80SAxel Dörfler	info.client_token = ClientToken();
4666a0a0a80SAxel Dörfler	info.client_port = fClientLooperPort;
467953d895eSAxel Dörfler	info.workspaces = fWindow->Workspaces();
4686a0a0a80SAxel Dörfler
46944cd4a02SAxel Dörfler	// logic taken from Switcher comments and experiments
47044cd4a02SAxel Dörfler	if (fWindow->IsHidden())
47144cd4a02SAxel Dörfler		info.layer = 0;
47244cd4a02SAxel Dörfler	else if (fWindow->IsVisible()) {
47344cd4a02SAxel Dörfler		if (fWindow->Feel() == kDesktopWindowFeel)
47444cd4a02SAxel Dörfler			info.layer = 2;
47544cd4a02SAxel Dörfler		else if (fWindow->IsFloating() || fWindow->IsModal())
47644cd4a02SAxel Dörfler			info.layer = 4;
47744cd4a02SAxel Dörfler		else
47844cd4a02SAxel Dörfler			info.layer = 3;
47944cd4a02SAxel Dörfler	} else
48044cd4a02SAxel Dörfler		info.layer = 1;
48144cd4a02SAxel Dörfler
482953d895eSAxel Dörfler	info.feel = fWindow->Feel();
483953d895eSAxel Dörfler	info.flags = fWindow->Flags();
484953d895eSAxel Dörfler	info.window_left = (int)floor(fWindow->Frame().left);
485953d895eSAxel Dörfler	info.window_top = (int)floor(fWindow->Frame().top);
486953d895eSAxel Dörfler	info.window_right = (int)floor(fWindow->Frame().right);
487953d895eSAxel Dörfler	info.window_bottom = (int)floor(fWindow->Frame().bottom);
488953d895eSAxel Dörfler
48959347b7fSRyan Leavengood	info.show_hide_level = fWindow->ShowLevel();
490953d895eSAxel Dörfler	info.is_mini = fWindow->IsMinimized();
4916a0a0a80SAxel Dörfler}
4926a0a0a80SAxel Dörfler
4936a0a0a80SAxel Dörfler
4940896fce5SStephan Aßmusvoid
4950896fce5SStephan AßmusServerWindow::ResyncDrawState()
4960896fce5SStephan Aßmus{
497953d895eSAxel Dörfler	_UpdateDrawState(fCurrentView);
4980896fce5SStephan Aßmus}
4990896fce5SStephan Aßmus
5000896fce5SStephan Aßmus
501953d895eSAxel DörflerView*
50207e13b5fSAxel DörflerServerWindow::_CreateView(BPrivate::LinkReceiver& link, View** _parent)
50370e337a0SDarkWyrm{
5048491b626SAdi Oanca	// NOTE: no need to check for a lock. This is a private method.
50570e337a0SDarkWyrm
50670e337a0SDarkWyrm	int32 token;
50770e337a0SDarkWyrm	BRect frame;
50870e337a0SDarkWyrm	uint32 resizeMask;
509165177a1SAdi Oanca	uint32 eventMask;
510165177a1SAdi Oanca	uint32 eventOptions;
51170e337a0SDarkWyrm	uint32 flags;
51270e337a0SDarkWyrm	bool hidden;
51353442520SAxel Dörfler	int32 parentToken;
514e83820edSAxel Dörfler	char* name = NULL;
515b81c5513SAdi Oanca	rgb_color viewColor;
516903936bcSAxel Dörfler	BPoint scrollingOffset;
517280d1aacSAxel Dörfler
51837aec728SDarkWyrm	link.Read<int32>(&token);
51937aec728SDarkWyrm	link.ReadString(&name);
52037aec728SDarkWyrm	link.Read<BRect>(&frame);
521903936bcSAxel Dörfler	link.Read<BPoint>(&scrollingOffset);
52237aec728SDarkWyrm	link.Read<uint32>(&resizeMask);
523165177a1SAdi Oanca	link.Read<uint32>(&eventMask);
524165177a1SAdi Oanca	link.Read<uint32>(&eventOptions);
52537aec728SDarkWyrm	link.Read<uint32>(&flags);
52637aec728SDarkWyrm	link.Read<bool>(&hidden);
52753442520SAxel Dörfler	link.Read<rgb_color>(&viewColor);
52853442520SAxel Dörfler	link.Read<int32>(&parentToken);
529280d1aacSAxel Dörfler
5303fed1a15SAlex Smith	STRACE(("ServerWindow(%s)::_CreateView()-> view %s, token %" B_PRId32 "\n",
531a38e46a0SAxel Dörfler		fTitle, name, token));
532e438905aSAdi Oanca
533437b1927SAxel Dörfler	View* newView;
53424a146d4SAxel Dörfler
5352c184b20SAxel Dörfler	if ((flags & kWorkspacesViewFlag) != 0) {
536437b1927SAxel Dörfler		newView = new (nothrow) WorkspacesView(frame, scrollingOffset, name,
537903936bcSAxel Dörfler			token, resizeMask, flags);
53824a146d4SAxel Dörfler	} else {
539437b1927SAxel Dörfler		newView = new (nothrow) View(frame, scrollingOffset, name, token,
540903936bcSAxel Dörfler			resizeMask, flags);
54124a146d4SAxel Dörfler	}
542280d1aacSAxel Dörfler
543e83820edSAxel Dörfler	free(name);
544e83820edSAxel Dörfler
545437b1927SAxel Dörfler	if (newView == NULL)
5465abd5613SAxel Dörfler		return NULL;
5475abd5613SAxel Dörfler
548701dae79SStefano Ceccherini	if (newView->InitCheck() != B_OK) {
549701dae79SStefano Ceccherini		delete newView;
550701dae79SStefano Ceccherini		return NULL;
551701dae79SStefano Ceccherini	}
5520eed9183SAxel Dörfler
55370e337a0SDarkWyrm	// there is no way of setting this, other than manually :-)
554437b1927SAxel Dörfler	newView->SetViewColor(viewColor);
555437b1927SAxel Dörfler	newView->SetHidden(hidden);
556437b1927SAxel Dörfler	newView->SetEventMask(eventMask, eventOptions);
557c1255125SAdi Oanca
55866e114c4SAxel Dörfler	if (eventMask != 0 || eventOptions != 0) {
5594d1c4228SStephan Aßmus//		fDesktop->UnlockSingleWindow();
5604d1c4228SStephan Aßmus//		fDesktop->LockAllWindows();
5614d1c4228SStephan AßmusfDesktop->UnlockAllWindows();
5624d1c4228SStephan Aßmus		// TODO: possible deadlock
56366e114c4SAxel Dörfler		fDesktop->EventDispatcher().AddListener(EventTarget(),
564437b1927SAxel Dörfler			newView->Token(), eventMask, eventOptions);
5654d1c4228SStephan AßmusfDesktop->LockAllWindows();
5664d1c4228SStephan Aßmus//		fDesktop->UnlockAllWindows();
5674d1c4228SStephan Aßmus//		fDesktop->LockSingleWindow();
56866e114c4SAxel Dörfler	}
56966e114c4SAxel Dörfler
570fc235d55SStephan Aßmus	// Initialize the view with the current application plain font.
571fc235d55SStephan Aßmus	// NOTE: This might be out of sync with the global app_server plain
572fc235d55SStephan Aßmus	// font, but that is so on purpose! The client needs to resync itself
573fc235d55SStephan Aßmus	// with the app_server fonts upon notification, but if we just use
574fc235d55SStephan Aßmus	// the current font here, the be_plain_font on the client may still
575fc235d55SStephan Aßmus	// hold old values. So this needs to be an update initiated by the
576fc235d55SStephan Aßmus	// client application.
577fc235d55SStephan Aßmus	newView->CurrentState()->SetFont(App()->PlainFont());
5785abd5613SAxel Dörfler
57953442520SAxel Dörfler	if (_parent) {
580953d895eSAxel Dörfler		View *parent;
581bde8b9c6SAxel Dörfler		if (App()->ViewTokens().GetToken(parentToken, B_HANDLER_TOKEN,
582bde8b9c6SAxel Dörfler				(void**)&parent) != B_OK
583e83820edSAxel Dörfler			|| parent->Window()->ServerWindow() != this) {
584437b1927SAxel Dörfler			debug_printf("View token not found!\n");
585bde8b9c6SAxel Dörfler			parent = NULL;
586bde8b9c6SAxel Dörfler		}
58753442520SAxel Dörfler
58853442520SAxel Dörfler		*_parent = parent;
58953442520SAxel Dörfler	}
590ad56ce66SDarkWyrm
591437b1927SAxel Dörfler	return newView;
592c1255125SAdi Oanca}
593280d1aacSAxel Dörfler
594280d1aacSAxel Dörfler
59507e13b5fSAxel Dörfler/*!	Dispatches all window messages, and those view messages that
596437b1927SAxel Dörfler	don't need a valid fCurrentView (ie. view creation).
597e83820edSAxel Dörfler*/
598280d1aacSAxel Dörflervoid
599ea0ba618SAxel DörflerServerWindow::_DispatchMessage(int32 code, BPrivate::LinkReceiver& link)
600e8cde265SDarkWyrm{
601280d1aacSAxel Dörfler	switch (code) {
60259347b7fSRyan Leavengood		case AS_SHOW_OR_HIDE_WINDOW:
60396cabf58SRyan Leavengood		{
60496cabf58SRyan Leavengood			int32 showLevel;
60596cabf58SRyan Leavengood			if (link.Read<int32>(&showLevel) == B_OK) {
60659347b7fSRyan Leavengood				DTRACE(("ServerWindow %s: Message AS_SHOW_OR_HIDE_WINDOW, "
60735965e58SMichael Lotz					"show level: %" B_PRId32 "\n", Title(), showLevel));
60859347b7fSRyan Leavengood
60996cabf58SRyan Leavengood				fWindow->SetShowLevel(showLevel);
61059347b7fSRyan Leavengood				if (showLevel <= 0)
61159347b7fSRyan Leavengood					_Show();
61259347b7fSRyan Leavengood				else
61359347b7fSRyan Leavengood					_Hide();
61496cabf58SRyan Leavengood			}
615e83820edSAxel Dörfler			break;
61696cabf58SRyan Leavengood		}
61759347b7fSRyan Leavengood		// Only for internal use within this class
61859347b7fSRyan Leavengood		case AS_INTERNAL_HIDE_WINDOW:
619f8d8085dSAxel Dörfler			_Hide();
620db7226dbSStephan Aßmus			break;
621995ab7b3SAxel Dörfler		case AS_MINIMIZE_WINDOW:
622995ab7b3SAxel Dörfler		{
623995ab7b3SAxel Dörfler			bool minimize;
62496cabf58SRyan Leavengood			if (link.Read<bool>(&minimize) == B_OK) {
625e98ee141SStephan Aßmus				DTRACE(("ServerWindow %s: Message AS_MINIMIZE_WINDOW, "
62696cabf58SRyan Leavengood					"minimize: %d\n", Title(), minimize));
6279b5a1835SAxel Dörfler
628860dfc9aSClemens Zeidler				fDesktop->UnlockSingleWindow();
629860dfc9aSClemens Zeidler				fDesktop->MinimizeWindow(fWindow, minimize);
630860dfc9aSClemens Zeidler				fDesktop->LockSingleWindow();
631995ab7b3SAxel Dörfler			}
632995ab7b3SAxel Dörfler			break;
633995ab7b3SAxel Dörfler		}
634995ab7b3S