1/*
2 * Copyright 2001-2015, Haiku, Inc.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 *		DarkWyrm <bpmagic@columbus.rr.com>
7 *		Caz <turok2@currantbun.com>
8 *		Axel D��rfler, axeld@pinc-software.de
9 *		Michael Lotz <mmlr@mlotz.ch>
10 *		Wim van der Meer <WPJvanderMeer@gmail.com>
11 *		Joseph Groover <looncraz@looncraz.net>
12 */
13
14
15/*!	Global functions and variables for the Interface Kit */
16
17
18#include <InterfaceDefs.h>
19
20#include <new>
21#include <stdio.h>
22#include <stdlib.h>
23#include <string.h>
24
25#include <Bitmap.h>
26#include <Clipboard.h>
27#include <ControlLook.h>
28#include <Font.h>
29#include <Menu.h>
30#include <Point.h>
31#include <Roster.h>
32#include <Screen.h>
33#include <ScrollBar.h>
34#include <String.h>
35#include <TextView.h>
36#include <Window.h>
37
38#include <ApplicationPrivate.h>
39#include <AppServerLink.h>
40#include <ColorConversion.h>
41#include <DecorInfo.h>
42#include <DefaultColors.h>
43#include <DesktopLink.h>
44#include <HaikuControlLook.h>
45#include <InputServerTypes.h>
46#include <input_globals.h>
47#include <InterfacePrivate.h>
48#include <MenuPrivate.h>
49#include <pr_server.h>
50#include <ServerProtocol.h>
51#include <ServerReadOnlyMemory.h>
52#include <truncate_string.h>
53#include <utf8_functions.h>
54#include <WidthBuffer.h>
55#include <WindowInfo.h>
56
57
58using namespace BPrivate;
59
60// some other weird struct exported by BeOS, it's not initialized, though
61struct general_ui_info {
62	rgb_color	background_color;
63	rgb_color	mark_color;
64	rgb_color	highlight_color;
65	bool		color_frame;
66	rgb_color	window_frame_color;
67};
68
69struct general_ui_info general_info;
70
71menu_info *_menu_info_ptr_;
72
73extern "C" const char B_NOTIFICATION_SENDER[] = "be:sender";
74
75static const rgb_color _kDefaultColors[kColorWhichCount] = {
76	{216, 216, 216, 255},	// B_PANEL_BACKGROUND_COLOR
77	{216, 216, 216, 255},	// B_MENU_BACKGROUND_COLOR
78	{255, 203, 0, 255},		// B_WINDOW_TAB_COLOR
79	{0, 0, 229, 255},		// B_KEYBOARD_NAVIGATION_COLOR
80	{51, 102, 152, 255},	// B_DESKTOP_COLOR
81	{153, 153, 153, 255},	// B_MENU_SELECTED_BACKGROUND_COLOR
82	{0, 0, 0, 255},			// B_MENU_ITEM_TEXT_COLOR
83	{0, 0, 0, 255},			// B_MENU_SELECTED_ITEM_TEXT_COLOR
84	{0, 0, 0, 255},			// B_MENU_SELECTED_BORDER_COLOR
85	{0, 0, 0, 255},			// B_PANEL_TEXT_COLOR
86	{255, 255, 255, 255},	// B_DOCUMENT_BACKGROUND_COLOR
87	{0, 0, 0, 255},			// B_DOCUMENT_TEXT_COLOR
88	{245, 245, 245, 255},	// B_CONTROL_BACKGROUND_COLOR
89	{0, 0, 0, 255},			// B_CONTROL_TEXT_COLOR
90	{172, 172, 172, 255},	// B_CONTROL_BORDER_COLOR
91	{102, 152, 203, 255},	// B_CONTROL_HIGHLIGHT_COLOR
92	{0, 0, 0, 255},			// B_NAVIGATION_PULSE_COLOR
93	{255, 255, 255, 255},	// B_SHINE_COLOR
94	{0, 0, 0, 255},			// B_SHADOW_COLOR
95	{255, 255, 216, 255},	// B_TOOLTIP_BACKGROUND_COLOR
96	{0, 0, 0, 255},			// B_TOOLTIP_TEXT_COLOR
97	{0, 0, 0, 255},			// B_WINDOW_TEXT_COLOR
98	{232, 232, 232, 255},	// B_WINDOW_INACTIVE_TAB_COLOR
99	{80, 80, 80, 255},		// B_WINDOW_INACTIVE_TEXT_COLOR
100	{224, 224, 224, 255},	// B_WINDOW_BORDER_COLOR
101	{232, 232, 232, 255},	// B_WINDOW_INACTIVE_BORDER_COLOR
102	{27, 82, 140, 255},     // B_CONTROL_MARK_COLOR
103	{255, 255, 255, 255},	// B_LIST_BACKGROUND_COLOR
104	{190, 190, 190, 255},	// B_LIST_SELECTED_BACKGROUND_COLOR
105	{0, 0, 0, 255},			// B_LIST_ITEM_TEXT_COLOR
106	{0, 0, 0, 255},			// B_LIST_SELECTED_ITEM_TEXT_COLOR
107	{216, 216, 216, 255},	// B_SCROLL_BAR_THUMB_COLOR
108	{51, 102, 187, 255},	// B_LINK_TEXT_COLOR
109	{102, 152, 203, 255},	// B_LINK_HOVER_COLOR
110	{145, 112, 155, 255},	// B_LINK_VISITED_COLOR
111	{121, 142, 203, 255},	// B_LINK_ACTIVE_COLOR
112	{50, 150, 255, 255},	// B_STATUS_BAR_COLOR
113	// 100...
114	{46, 204, 64, 255},		// B_SUCCESS_COLOR
115	{255, 65, 54, 255},		// B_FAILURE_COLOR
116	{}
117};
118const rgb_color* BPrivate::kDefaultColors = &_kDefaultColors[0];
119
120
121static const rgb_color _kDefaultColorsDark[kColorWhichCount] = {
122	{43, 43, 43, 255},		// B_PANEL_BACKGROUND_COLOR
123	{28, 28, 28, 255},		// B_MENU_BACKGROUND_COLOR
124	{227, 73, 17, 255},		// B_WINDOW_TAB_COLOR
125	{0, 0, 229, 255},		// B_KEYBOARD_NAVIGATION_COLOR
126	{51, 102, 152, 255},	// B_DESKTOP_COLOR
127	{90, 90, 90, 255},		// B_MENU_SELECTED_BACKGROUND_COLOR
128	{255, 255, 255, 255},	// B_MENU_ITEM_TEXT_COLOR
129	{255, 255, 255, 255},	// B_MENU_SELECTED_ITEM_TEXT_COLOR
130	{0, 0, 0, 255},			// B_MENU_SELECTED_BORDER_COLOR
131	{253, 253, 253, 255},	// B_PANEL_TEXT_COLOR
132	{0, 0, 0, 255},			// B_DOCUMENT_BACKGROUND_COLOR
133	{234, 234, 234, 255},	// B_DOCUMENT_TEXT_COLOR
134	{29, 29, 29, 255},		// B_CONTROL_BACKGROUND_COLOR
135	{230, 230, 230, 255},	// B_CONTROL_TEXT_COLOR
136	{195, 195, 195, 255},	// B_CONTROL_BORDER_COLOR
137	{75, 124, 168, 255},	// B_CONTROL_HIGHLIGHT_COLOR
138	{0, 0, 0, 255},			// B_NAVIGATION_PULSE_COLOR
139	{255, 255, 255, 255},	// B_SHINE_COLOR
140	{0, 0, 0, 255},			// B_SHADOW_COLOR
141	{76, 68, 79, 255},		// B_TOOLTIP_BACKGROUND_COLOR
142	{255, 255, 255, 255},	// B_TOOLTIP_TEXT_COLOR
143	{255, 255, 255, 255},	// B_WINDOW_TEXT_COLOR
144	{203, 32, 9, 255},		// B_WINDOW_INACTIVE_TAB_COLOR
145	{255, 255, 255, 255},	// B_WINDOW_INACTIVE_TEXT_COLOR
146	{227, 73, 17, 255},		// B_WINDOW_BORDER_COLOR
147	{203, 32, 9, 255},		// B_WINDOW_INACTIVE_BORDER_COLOR
148	{27, 82, 140, 255},     // B_CONTROL_MARK_COLOR
149	{0, 0, 0, 255},			// B_LIST_BACKGROUND_COLOR
150	{90, 90, 90, 255},		// B_LIST_SELECTED_BACKGROUND_COLOR
151	{255, 255, 255, 255},	// B_LIST_ITEM_TEXT_COLOR
152	{255, 255, 255, 255},	// B_LIST_SELECTED_ITEM_TEXT_COLOR
153	{39, 39, 39, 255},		// B_SCROLL_BAR_THUMB_COLOR
154	{106, 112, 212, 255},	// B_LINK_TEXT_COLOR
155	{102, 152, 203, 255},	// B_LINK_HOVER_COLOR
156	{145, 112, 155, 255},	// B_LINK_VISITED_COLOR
157	{121, 142, 203, 255},	// B_LINK_ACTIVE_COLOR
158	{50, 150, 255, 255},	// B_STATUS_BAR_COLOR
159	// 100...
160	{46, 204, 64, 255},		// B_SUCCESS_COLOR
161	{255, 40, 54, 255},		// B_FAILURE_COLOR
162	{}
163};
164
165
166static const char* kColorNames[kColorWhichCount] = {
167	"B_PANEL_BACKGROUND_COLOR",
168	"B_MENU_BACKGROUND_COLOR",
169	"B_WINDOW_TAB_COLOR",
170	"B_KEYBOARD_NAVIGATION_COLOR",
171	"B_DESKTOP_COLOR",
172	"B_MENU_SELECTED_BACKGROUND_COLOR",
173	"B_MENU_ITEM_TEXT_COLOR",
174	"B_MENU_SELECTED_ITEM_TEXT_COLOR",
175	"B_MENU_SELECTED_BORDER_COLOR",
176	"B_PANEL_TEXT_COLOR",
177	"B_DOCUMENT_BACKGROUND_COLOR",
178	"B_DOCUMENT_TEXT_COLOR",
179	"B_CONTROL_BACKGROUND_COLOR",
180	"B_CONTROL_TEXT_COLOR",
181	"B_CONTROL_BORDER_COLOR",
182	"B_CONTROL_HIGHLIGHT_COLOR",
183	"B_NAVIGATION_PULSE_COLOR",
184	"B_SHINE_COLOR",
185	"B_SHADOW_COLOR",
186	"B_TOOLTIP_BACKGROUND_COLOR",
187	"B_TOOLTIP_TEXT_COLOR",
188	"B_WINDOW_TEXT_COLOR",
189	"B_WINDOW_INACTIVE_TAB_COLOR",
190	"B_WINDOW_INACTIVE_TEXT_COLOR",
191	"B_WINDOW_BORDER_COLOR",
192	"B_WINDOW_INACTIVE_BORDER_COLOR",
193	"B_CONTROL_MARK_COLOR",
194	"B_LIST_BACKGROUND_COLOR",
195	"B_LIST_SELECTED_BACKGROUND_COLOR",
196	"B_LIST_ITEM_TEXT_COLOR",
197	"B_LIST_SELECTED_ITEM_TEXT_COLOR",
198	"B_SCROLL_BAR_THUMB_COLOR",
199	"B_LINK_TEXT_COLOR",
200	"B_LINK_HOVER_COLOR",
201	"B_LINK_VISITED_COLOR",
202	"B_LINK_ACTIVE_COLOR",
203	"B_STATUS_BAR_COLOR",
204	// 100...
205	"B_SUCCESS_COLOR",
206	"B_FAILURE_COLOR",
207	NULL
208};
209
210static image_id sControlLookAddon = -1;
211
212
213namespace BPrivate {
214
215
216/*!	Fills the \a width, \a height, and \a colorSpace parameters according
217	to the window screen's mode.
218	Returns \c true if the mode is known.
219*/
220bool
221get_mode_parameter(uint32 mode, int32& width, int32& height,
222	uint32& colorSpace)
223{
224	switch (mode) {
225		case B_8_BIT_640x480:
226		case B_8_BIT_800x600:
227		case B_8_BIT_1024x768:
228		case B_8_BIT_1152x900:
229		case B_8_BIT_1280x1024:
230		case B_8_BIT_1600x1200:
231			colorSpace = B_CMAP8;
232			break;
233
234		case B_15_BIT_640x480:
235		case B_15_BIT_800x600:
236		case B_15_BIT_1024x768:
237		case B_15_BIT_1152x900:
238		case B_15_BIT_1280x1024:
239		case B_15_BIT_1600x1200:
240			colorSpace = B_RGB15;
241			break;
242
243		case B_16_BIT_640x480:
244		case B_16_BIT_800x600:
245		case B_16_BIT_1024x768:
246		case B_16_BIT_1152x900:
247		case B_16_BIT_1280x1024:
248		case B_16_BIT_1600x1200:
249			colorSpace = B_RGB16;
250			break;
251
252		case B_32_BIT_640x480:
253		case B_32_BIT_800x600:
254		case B_32_BIT_1024x768:
255		case B_32_BIT_1152x900:
256		case B_32_BIT_1280x1024:
257		case B_32_BIT_1600x1200:
258			colorSpace = B_RGB32;
259			break;
260
261		default:
262			return false;
263	}
264
265	switch (mode) {
266		case B_8_BIT_640x480:
267		case B_15_BIT_640x480:
268		case B_16_BIT_640x480:
269		case B_32_BIT_640x480:
270			width = 640; height = 480;
271			break;
272
273		case B_8_BIT_800x600:
274		case B_15_BIT_800x600:
275		case B_16_BIT_800x600:
276		case B_32_BIT_800x600:
277			width = 800; height = 600;
278			break;
279
280		case B_8_BIT_1024x768:
281		case B_15_BIT_1024x768:
282		case B_16_BIT_1024x768:
283		case B_32_BIT_1024x768:
284			width = 1024; height = 768;
285			break;
286
287		case B_8_BIT_1152x900:
288		case B_15_BIT_1152x900:
289		case B_16_BIT_1152x900:
290		case B_32_BIT_1152x900:
291			width = 1152; height = 900;
292			break;
293
294		case B_8_BIT_1280x1024:
295		case B_15_BIT_1280x1024:
296		case B_16_BIT_1280x1024:
297		case B_32_BIT_1280x1024:
298			width = 1280; height = 1024;
299			break;
300
301		case B_8_BIT_1600x1200:
302		case B_15_BIT_1600x1200:
303		case B_16_BIT_1600x1200:
304		case B_32_BIT_1600x1200:
305			width = 1600; height = 1200;
306			break;
307	}
308
309	return true;
310}
311
312
313void
314get_workspaces_layout(uint32* _columns, uint32* _rows)
315{
316	int32 columns = 1;
317	int32 rows = 1;
318
319	BPrivate::AppServerLink link;
320	link.StartMessage(AS_GET_WORKSPACE_LAYOUT);
321
322	status_t status;
323	if (link.FlushWithReply(status) == B_OK && status == B_OK) {
324		link.Read<int32>(&columns);
325		link.Read<int32>(&rows);
326	}
327
328	if (_columns != NULL)
329		*_columns = columns;
330	if (_rows != NULL)
331		*_rows = rows;
332}
333
334
335void
336set_workspaces_layout(uint32 columns, uint32 rows)
337{
338	if (columns < 1 || rows < 1)
339		return;
340
341	BPrivate::AppServerLink link;
342	link.StartMessage(AS_SET_WORKSPACE_LAYOUT);
343	link.Attach<int32>(columns);
344	link.Attach<int32>(rows);
345	link.Flush();
346}
347
348
349}	// namespace BPrivate
350
351
352void
353set_subpixel_antialiasing(bool subpix)
354{
355	BPrivate::AppServerLink link;
356
357	link.StartMessage(AS_SET_SUBPIXEL_ANTIALIASING);
358	link.Attach<bool>(subpix);
359	link.Flush();
360}
361
362
363status_t
364get_subpixel_antialiasing(bool* subpix)
365{
366	BPrivate::AppServerLink link;
367
368	link.StartMessage(AS_GET_SUBPIXEL_ANTIALIASING);
369	int32 status = B_ERROR;
370	if (link.FlushWithReply(status) != B_OK || status < B_OK)
371		return status;
372	link.Read<bool>(subpix);
373	return B_OK;
374}
375
376
377void
378set_hinting_mode(uint8 hinting)
379{
380	BPrivate::AppServerLink link;
381
382	link.StartMessage(AS_SET_HINTING);
383	link.Attach<uint8>(hinting);
384	link.Flush();
385}
386
387
388status_t
389get_hinting_mode(uint8* hinting)
390{
391	BPrivate::AppServerLink link;
392
393	link.StartMessage(AS_GET_HINTING);
394	int32 status = B_ERROR;
395	if (link.FlushWithReply(status) != B_OK || status < B_OK)
396		return status;
397	link.Read<uint8>(hinting);
398	return B_OK;
399}
400
401
402void
403set_average_weight(uint8 averageWeight)
404{
405	BPrivate::AppServerLink link;
406
407	link.StartMessage(AS_SET_SUBPIXEL_AVERAGE_WEIGHT);
408	link.Attach<uint8>(averageWeight);
409	link.Flush();
410}
411
412
413status_t
414get_average_weight(uint8* averageWeight)
415{
416	BPrivate::AppServerLink link;
417
418	link.StartMessage(AS_GET_SUBPIXEL_AVERAGE_WEIGHT);
419	int32 status = B_ERROR;
420	if (link.FlushWithReply(status) != B_OK || status < B_OK)
421		return status;
422	link.Read<uint8>(averageWeight);
423	return B_OK;
424}
425
426
427void
428set_is_subpixel_ordering_regular(bool subpixelOrdering)
429{
430	BPrivate::AppServerLink link;
431
432	link.StartMessage(AS_SET_SUBPIXEL_ORDERING);
433	link.Attach<bool>(subpixelOrdering);
434	link.Flush();
435}
436
437
438status_t
439get_is_subpixel_ordering_regular(bool* subpixelOrdering)
440{
441	BPrivate::AppServerLink link;
442
443	link.StartMessage(AS_GET_SUBPIXEL_ORDERING);
444	int32 status = B_ERROR;
445	if (link.FlushWithReply(status) != B_OK || status < B_OK)
446		return status;
447	link.Read<bool>(subpixelOrdering);
448	return B_OK;
449}
450
451
452const color_map *
453system_colors()
454{
455	return BScreen(B_MAIN_SCREEN_ID).ColorMap();
456}
457
458
459status_t
460set_screen_space(int32 index, uint32 space, bool stick)
461{
462	int32 width;
463	int32 height;
464	uint32 depth;
465	if (!BPrivate::get_mode_parameter(space, width, height, depth))
466		return B_BAD_VALUE;
467
468	BScreen screen(B_MAIN_SCREEN_ID);
469	display_mode mode;
470
471	// TODO: What about refresh rate ?
472	// currently we get it from the current video mode, but
473	// this might be not so wise.
474	status_t status = screen.GetMode(index, &mode);
475	if (status < B_OK)
476		return status;
477
478	mode.virtual_width = width;
479	mode.virtual_height = height;
480	mode.space = depth;
481
482	return screen.SetMode(index, &mode, stick);
483}
484
485
486status_t
487get_scroll_bar_info(scroll_bar_info *info)
488{
489	if (info == NULL)
490		return B_BAD_VALUE;
491
492	BPrivate::AppServerLink link;
493	link.StartMessage(AS_GET_SCROLLBAR_INFO);
494
495	int32 code;
496	if (link.FlushWithReply(code) == B_OK
497		&& code == B_OK) {
498		link.Read<scroll_bar_info>(info);
499		return B_OK;
500	}
501
502	return B_ERROR;
503}
504
505
506status_t
507set_scroll_bar_info(scroll_bar_info *info)
508{
509	if (info == NULL)
510		return B_BAD_VALUE;
511
512	BPrivate::AppServerLink link;
513	int32 code;
514
515	link.StartMessage(AS_SET_SCROLLBAR_INFO);
516	link.Attach<scroll_bar_info>(*info);
517
518	if (link.FlushWithReply(code) == B_OK
519		&& code == B_OK)
520		return B_OK;
521
522	return B_ERROR;
523}
524
525
526status_t
527get_mouse_type(int32 *type)
528{
529	BMessage command(IS_GET_MOUSE_TYPE);
530	BMessage reply;
531
532	status_t err = _control_input_server_(&command, &reply);
533	if (err != B_OK)
534		return err;
535	return reply.FindInt32("mouse_type", type);
536}
537
538
539status_t
540set_mouse_type(int32 type)
541{
542	BMessage command(IS_SET_MOUSE_TYPE);
543	BMessage reply;
544
545	status_t err = command.AddInt32("mouse_type", type);
546	if (err != B_OK)
547		return err;
548	return _control_input_server_(&command, &reply);
549}
550
551
552status_t
553get_mouse_type(const char* mouse_name, int32 *type)
554{
555	BMessage command(IS_GET_MOUSE_TYPE);
556	BMessage reply;
557	command.AddString("mouse_name", mouse_name);
558
559	status_t err = _control_input_server_(&command, &reply);
560	if (err != B_OK)
561		return err;
562
563	return reply.FindInt32("mouse_type", type);
564}
565
566
567status_t
568set_mouse_type(const char* mouse_name, int32 type)
569{
570	BMessage command(IS_SET_MOUSE_TYPE);
571	BMessage reply;
572
573	status_t err_mouse_name = command.AddString("mouse_name", mouse_name);
574	if (err_mouse_name != B_OK)
575		return err_mouse_name;
576
577	status_t err = command.AddInt32("mouse_type", type);
578	if (err != B_OK)
579		return err;
580	return _control_input_server_(&command, &reply);
581}
582
583
584status_t
585get_mouse_map(mouse_map *map)
586{
587	BMessage command(IS_GET_MOUSE_MAP);
588	BMessage reply;
589	const void *data = 0;
590	ssize_t count;
591
592	status_t err = _control_input_server_(&command, &reply);
593	if (err == B_OK)
594		err = reply.FindData("mousemap", B_RAW_TYPE, &data, &count);
595	if (err != B_OK)
596		return err;
597
598	memcpy(map, data, count);
599
600	return B_OK;
601}
602
603
604status_t
605set_mouse_map(mouse_map *map)
606{
607	BMessage command(IS_SET_MOUSE_MAP);
608	BMessage reply;
609
610	status_t err = command.AddData("mousemap", B_RAW_TYPE, map,
611		sizeof(mouse_map));
612	if (err != B_OK)
613		return err;
614	return _control_input_server_(&command, &reply);
615}
616
617
618status_t
619get_click_speed(bigtime_t *speed)
620{
621	BMessage command(IS_GET_CLICK_SPEED);
622	BMessage reply;
623
624	status_t err = _control_input_server_(&command, &reply);
625	if (err != B_OK)
626		return err;
627
628	if (reply.FindInt64("speed", speed) != B_OK)
629		*speed = 500000;
630
631	return B_OK;
632}
633
634
635status_t
636set_click_speed(bigtime_t speed)
637{
638	BMessage command(IS_SET_CLICK_SPEED);
639	BMessage reply;
640	command.AddInt64("speed", speed);
641	return _control_input_server_(&command, &reply);
642}
643
644
645status_t
646get_mouse_speed(int32 *speed)
647{
648	BMessage command(IS_GET_MOUSE_SPEED);
649	BMessage reply;
650
651	status_t err = _control_input_server_(&command, &reply);
652	if (err != B_OK)
653		return err;
654
655	if (reply.FindInt32("speed", speed) != B_OK)
656		*speed = 65536;
657
658	return B_OK;
659}
660
661
662status_t
663set_mouse_speed(int32 speed)
664{
665	BMessage command(IS_SET_MOUSE_SPEED);
666	BMessage reply;
667	command.AddInt32("speed", speed);
668	return _control_input_server_(&command, &reply);
669}
670
671
672status_t
673get_mouse_speed(const char* mouse_name, int32 *speed)
674{
675	BMessage command(IS_GET_MOUSE_SPEED);
676	BMessage reply;
677	command.AddString("mouse_name", mouse_name);
678
679	status_t err = _control_input_server_(&command, &reply);
680	if (err != B_OK)
681		return err;
682
683	err = reply.FindInt32("speed", speed);
684	if (err != B_OK)
685		return err;
686
687	return B_OK;
688}
689
690
691status_t
692set_mouse_speed(const char* mouse_name, int32 speed)
693{
694	BMessage command(IS_SET_MOUSE_SPEED);
695	BMessage reply;
696	command.AddString("mouse_name", mouse_name);
697
698	command.AddInt32("speed", speed);
699
700	return _control_input_server_(&command, &reply);
701}
702
703
704status_t
705get_mouse_acceleration(int32 *speed)
706{
707	BMessage command(IS_GET_MOUSE_ACCELERATION);
708	BMessage reply;
709
710	_control_input_server_(&command, &reply);
711
712	if (reply.FindInt32("speed", speed) != B_OK)
713		*speed = 65536;
714
715	return B_OK;
716}
717
718
719status_t
720set_mouse_acceleration(int32 speed)
721{
722	BMessage command(IS_SET_MOUSE_ACCELERATION);
723	BMessage reply;
724	command.AddInt32("speed", speed);
725	return _control_input_server_(&command, &reply);
726}
727
728
729status_t
730get_mouse_acceleration(const char* mouse_name, int32 *speed)
731{
732	BMessage command(IS_GET_MOUSE_ACCELERATION);
733	BMessage reply;
734	command.AddString("mouse_name", mouse_name);
735
736	_control_input_server_(&command, &reply);
737
738	if (reply.FindInt32("speed", speed) != B_OK)
739		*speed = 65536;
740
741	return B_OK;
742}
743
744
745status_t
746set_mouse_acceleration(const char* mouse_name, int32 speed)
747{
748	BMessage command(IS_SET_MOUSE_ACCELERATION);
749	BMessage reply;
750	command.AddString("mouse_name", mouse_name);
751
752	command.AddInt32("speed", speed);
753
754	return _control_input_server_(&command, &reply);
755}
756
757
758status_t
759get_key_repeat_rate(int32 *rate)
760{
761	BMessage command(IS_GET_KEY_REPEAT_RATE);
762	BMessage reply;
763
764	status_t err = _control_input_server_(&command, &reply);
765
766	if (err == B_OK)
767		err = reply.FindInt32("rate", rate);
768
769	if (err != B_OK) {
770		*rate = 250000;
771		return err;
772	}
773
774	return B_OK;
775}
776
777
778status_t
779set_key_repeat_rate(int32 rate)
780{
781	BMessage command(IS_SET_KEY_REPEAT_RATE);
782	BMessage reply;
783	command.AddInt32("rate", rate);
784	return _control_input_server_(&command, &reply);
785}
786
787
788status_t
789get_key_repeat_delay(bigtime_t *delay)
790{
791	BMessage command(IS_GET_KEY_REPEAT_DELAY);
792	BMessage reply;
793
794	status_t err = _control_input_server_(&command, &reply);
795
796	if (err == B_OK)
797		err = reply.FindInt64("delay", delay);
798
799	if (err != B_OK) {
800		*delay = 200;
801		return err;
802	}
803
804	return B_OK;
805}
806
807
808status_t
809set_key_repeat_delay(bigtime_t  delay)
810{
811	BMessage command(IS_SET_KEY_REPEAT_DELAY);
812	BMessage reply;
813	command.AddInt64("delay", delay);
814	return _control_input_server_(&command, &reply);
815}
816
817
818uint32
819modifiers()
820{
821	BMessage command(IS_GET_MODIFIERS);
822	BMessage reply;
823	int32 err, modifier;
824
825	_control_input_server_(&command, &reply);
826
827	if (reply.FindInt32("status", &err) != B_OK)
828		return 0;
829
830	if (reply.FindInt32("modifiers", &modifier) != B_OK)
831		return 0;
832
833	return modifier;
834}
835
836
837status_t
838get_key_info(key_info *info)
839{
840	BMessage command(IS_GET_KEY_INFO);
841	BMessage reply;
842	const void *data = 0;
843	int32 err;
844	ssize_t count;
845
846	_control_input_server_(&command, &reply);
847
848	if (reply.FindInt32("status", &err) != B_OK)
849		return B_ERROR;
850
851	if (reply.FindData("key_info", B_ANY_TYPE, &data, &count) != B_OK)
852		return B_ERROR;
853
854	memcpy(info, data, count);
855	return B_OK;
856}
857
858
859void
860get_key_map(key_map **map, char **key_buffer)
861{
862	_get_key_map(map, key_buffer, NULL);
863}
864
865
866void
867_get_key_map(key_map **map, char **key_buffer, ssize_t *key_buffer_size)
868{
869	BMessage command(IS_GET_KEY_MAP);
870	BMessage reply;
871	ssize_t map_count, key_count;
872	const void *map_array = 0, *key_array = 0;
873	if (key_buffer_size == NULL)
874		key_buffer_size = &key_count;
875
876	_control_input_server_(&command, &reply);
877
878	if (reply.FindData("keymap", B_ANY_TYPE, &map_array, &map_count) != B_OK) {
879		*map = 0; *key_buffer = 0;
880		return;
881	}
882
883	if (reply.FindData("key_buffer", B_ANY_TYPE, &key_array, key_buffer_size)
884			!= B_OK) {
885		*map = 0; *key_buffer = 0;
886		return;
887	}
888
889	*map = (key_map *)malloc(map_count);
890	memcpy(*map, map_array, map_count);
891	*key_buffer = (char *)malloc(*key_buffer_size);
892	memcpy(*key_buffer, key_array, *key_buffer_size);
893}
894
895
896status_t
897get_keyboard_id(uint16 *id)
898{
899	BMessage command(IS_GET_KEYBOARD_ID);
900	BMessage reply;
901	uint16 kid;
902
903	_control_input_server_(&command, &reply);
904
905	status_t err = reply.FindInt16("id", (int16 *)&kid);
906	if (err != B_OK)
907		return err;
908	*id = kid;
909
910	return B_OK;
911}
912
913
914status_t
915get_modifier_key(uint32 modifier, uint32 *key)
916{
917	BMessage command(IS_GET_MODIFIER_KEY);
918	BMessage reply;
919	uint32 rkey;
920
921	command.AddInt32("modifier", modifier);
922	_control_input_server_(&command, &reply);
923
924	status_t err = reply.FindInt32("key", (int32 *) &rkey);
925	if (err != B_OK)
926		return err;
927	*key = rkey;
928
929	return B_OK;
930}
931
932
933void
934set_modifier_key(uint32 modifier, uint32 key)
935{
936	BMessage command(IS_SET_MODIFIER_KEY);
937	BMessage reply;
938
939	command.AddInt32("modifier", modifier);
940	command.AddInt32("key", key);
941	_control_input_server_(&command, &reply);
942}
943
944
945void
946set_keyboard_locks(uint32 modifiers)
947{
948	BMessage command(IS_SET_KEYBOARD_LOCKS);
949	BMessage reply;
950
951	command.AddInt32("locks", modifiers);
952	_control_input_server_(&command, &reply);
953}
954
955
956status_t
957_restore_key_map_()
958{
959	BMessage message(IS_RESTORE_KEY_MAP);
960	BMessage reply;
961
962	return _control_input_server_(&message, &reply);
963}
964
965
966rgb_color
967keyboard_navigation_color()
968{
969	// Queries the app_server
970	return ui_color(B_KEYBOARD_NAVIGATION_COLOR);
971}
972
973
974int32
975count_workspaces()
976{
977	uint32 columns;
978	uint32 rows;
979	BPrivate::get_workspaces_layout(&columns, &rows);
980
981	return columns * rows;
982}
983
984
985void
986set_workspace_count(int32 count)
987{
988	int32 squareRoot = (int32)sqrt(count);
989
990	int32 rows = 1;
991	for (int32 i = 2; i <= squareRoot; i++) {
992		if (count % i == 0)
993			rows = i;
994	}
995
996	int32 columns = count / rows;
997
998	BPrivate::set_workspaces_layout(columns, rows);
999}
1000
1001
1002int32
1003current_workspace()
1004{
1005	int32 index = 0;
1006
1007	BPrivate::AppServerLink link;
1008	link.StartMessage(AS_CURRENT_WORKSPACE);
1009
1010	int32 status;
1011	if (link.FlushWithReply(status) == B_OK && status == B_OK)
1012		link.Read<int32>(&index);
1013
1014	return index;
1015}
1016
1017
1018void
1019activate_workspace(int32 workspace)
1020{
1021	BPrivate::AppServerLink link;
1022	link.StartMessage(AS_ACTIVATE_WORKSPACE);
1023	link.Attach<int32>(workspace);
1024	link.Attach<bool>(false);
1025	link.Flush();
1026}
1027
1028
1029bigtime_t
1030idle_time()
1031{
1032	bigtime_t idletime = 0;
1033
1034	BPrivate::AppServerLink link;
1035	link.StartMessage(AS_IDLE_TIME);
1036
1037	int32 code;
1038	if (link.FlushWithReply(code) == B_OK && code == B_OK)
1039		link.Read<int64>(&idletime);
1040
1041	return idletime;
1042}
1043
1044
1045void
1046run_select_printer_panel()
1047{
1048	if (be_roster == NULL)
1049		return;
1050
1051	// Launches the Printer prefs app via the Roster
1052	be_roster->Launch(PRNT_SIGNATURE_TYPE);
1053}
1054
1055
1056void
1057run_add_printer_panel()
1058{
1059	// Launches the Printer prefs app via the Roster and asks it to
1060	// add a printer
1061	run_select_printer_panel();
1062
1063	BMessenger printerPanelMessenger(PRNT_SIGNATURE_TYPE);
1064	printerPanelMessenger.SendMessage(PRINTERS_ADD_PRINTER);
1065}
1066
1067
1068void
1069run_be_about()
1070{
1071	if (be_roster != NULL)
1072		be_roster->Launch("application/x-vnd.Haiku-About");
1073}
1074
1075
1076void
1077set_focus_follows_mouse(bool follow)
1078{
1079	// obviously deprecated API
1080	set_mouse_mode(follow ? B_FOCUS_FOLLOWS_MOUSE : B_NORMAL_MOUSE);
1081}
1082
1083
1084bool
1085focus_follows_mouse()
1086{
1087	return mouse_mode() == B_FOCUS_FOLLOWS_MOUSE;
1088}
1089
1090
1091void
1092set_mouse_mode(mode_mouse mode)
1093{
1094	BPrivate::AppServerLink link;
1095	link.StartMessage(AS_SET_MOUSE_MODE);
1096	link.Attach<mode_mouse>(mode);
1097	link.Flush();
1098}
1099
1100
1101mode_mouse
1102mouse_mode()
1103{
1104	// Gets the mouse focus style, such as activate to click,
1105	// focus to click, ...
1106	mode_mouse mode = B_NORMAL_MOUSE;
1107
1108	BPrivate::AppServerLink link;
1109	link.StartMessage(AS_GET_MOUSE_MODE);
1110
1111	int32 code;
1112	if (link.FlushWithReply(code) == B_OK && code == B_OK)
1113		link.Read<mode_mouse>(&mode);
1114
1115	return mode;
1116}
1117
1118
1119void
1120set_focus_follows_mouse_mode(mode_focus_follows_mouse mode)
1121{
1122	BPrivate::AppServerLink link;
1123	link.StartMessage(AS_SET_FOCUS_FOLLOWS_MOUSE_MODE);
1124	link.Attach<mode_focus_follows_mouse>(mode);
1125	link.Flush();
1126}
1127
1128
1129mode_focus_follows_mouse
1130focus_follows_mouse_mode()
1131{
1132	mode_focus_follows_mouse mode = B_NORMAL_FOCUS_FOLLOWS_MOUSE;
1133
1134	BPrivate::AppServerLink link;
1135	link.StartMessage(AS_GET_FOCUS_FOLLOWS_MOUSE_MODE);
1136
1137	int32 code;
1138	if (link.FlushWithReply(code) == B_OK && code == B_OK)
1139		link.Read<mode_focus_follows_mouse>(&mode);
1140
1141	return mode;
1142}
1143
1144
1145status_t
1146get_mouse(BPoint* screenWhere, uint32* buttons)
1147{
1148	if (screenWhere == NULL && buttons == NULL)
1149		return B_BAD_VALUE;
1150
1151	BPrivate::AppServerLink link;
1152	link.StartMessage(AS_GET_CURSOR_POSITION);
1153
1154	int32 code;
1155	status_t ret = link.FlushWithReply(code);
1156	if (ret != B_OK)
1157		return ret;
1158	if (code != B_OK)
1159		return code;
1160
1161	if (screenWhere != NULL)
1162		ret = link.Read<BPoint>(screenWhere);
1163	else {
1164		BPoint dummy;
1165		ret = link.Read<BPoint>(&dummy);
1166	}
1167	if (ret != B_OK)
1168		return ret;
1169
1170	if (buttons != NULL)
1171		ret = link.Read<uint32>(buttons);
1172	else {
1173		uint32 dummy;
1174		ret = link.Read<uint32>(&dummy);
1175	}
1176
1177	return ret;
1178}
1179
1180
1181status_t
1182get_mouse_bitmap(BBitmap** bitmap, BPoint* hotspot)
1183{
1184	if (bitmap == NULL && hotspot == NULL)
1185		return B_BAD_VALUE;
1186
1187	BPrivate::AppServerLink link;
1188	link.StartMessage(AS_GET_CURSOR_BITMAP);
1189
1190	int32 code;
1191	status_t status = link.FlushWithReply(code);
1192	if (status != B_OK)
1193		return status;
1194	if (code != B_OK)
1195		return code;
1196
1197	uint32 size = 0;
1198	uint32 cursorWidth = 0;
1199	uint32 cursorHeight = 0;
1200	color_space colorspace = B_RGBA32;
1201
1202	// if link.Read() returns an error, the same error will be returned on
1203	// subsequent calls, so we'll check only the return value of the last call
1204	link.Read<uint32>(&size);
1205	link.Read<uint32>(&cursorWidth);
1206	link.Read<uint32>(&cursorHeight);
1207	link.Read<color_space>(&colorspace);
1208	if (hotspot == NULL) {
1209		BPoint dummy;
1210		link.Read<BPoint>(&dummy);
1211	} else
1212		link.Read<BPoint>(hotspot);
1213
1214	void* data = NULL;
1215	if (size > 0)
1216		data = malloc(size);
1217	if (data == NULL)
1218		return B_NO_MEMORY;
1219
1220	status = link.Read(data, size);
1221	if (status != B_OK) {
1222		free(data);
1223		return status;
1224	}
1225
1226	BBitmap* cursorBitmap = new (std::nothrow) BBitmap(BRect(0, 0,
1227		cursorWidth - 1, cursorHeight - 1), colorspace);
1228
1229	if (cursorBitmap == NULL) {
1230		free(data);
1231		return B_NO_MEMORY;
1232	}
1233	status = cursorBitmap->InitCheck();
1234	if (status == B_OK)
1235		cursorBitmap->SetBits(data, size, 0, colorspace);
1236
1237	free(data);
1238
1239	if (status == B_OK && bitmap != NULL)
1240		*bitmap = cursorBitmap;
1241	else
1242		delete cursorBitmap;
1243
1244	return status;
1245}
1246
1247
1248void
1249set_accept_first_click(bool acceptFirstClick)
1250{
1251	BPrivate::AppServerLink link;
1252	link.StartMessage(AS_SET_ACCEPT_FIRST_CLICK);
1253	link.Attach<bool>(acceptFirstClick);
1254	link.Flush();
1255}
1256
1257
1258bool
1259accept_first_click()
1260{
1261	// Gets the accept first click status
1262	bool acceptFirstClick = true;
1263
1264	BPrivate::AppServerLink link;
1265	link.StartMessage(AS_GET_ACCEPT_FIRST_CLICK);
1266
1267	int32 code;
1268	if (link.FlushWithReply(code) == B_OK && code == B_OK)
1269		link.Read<bool>(&acceptFirstClick);
1270
1271	return acceptFirstClick;
1272}
1273
1274
1275rgb_color
1276ui_color(color_which which)
1277{
1278	int32 index = color_which_to_index(which);
1279	if (index < 0 || index >= kColorWhichCount) {
1280		fprintf(stderr, "ui_color(): unknown color_which %d\n", which);
1281		return make_color(0, 0, 0);
1282	}
1283
1284	if (be_app != NULL) {
1285		server_read_only_memory* shared
1286			= BApplication::Private::ServerReadOnlyMemory();
1287		if (shared != NULL) {
1288			// check for unset colors
1289			if (shared->colors[index] == B_TRANSPARENT_COLOR)
1290				shared->colors[index] = _kDefaultColors[index];
1291
1292			return shared->colors[index];
1293		}
1294	}
1295
1296	return _kDefaultColors[index];
1297}
1298
1299
1300rgb_color
1301BPrivate::GetSystemColor(color_which colorConstant, bool darkVariant) {
1302	if (darkVariant) {
1303		return _kDefaultColorsDark[color_which_to_index(colorConstant)];
1304	} else {
1305		return _kDefaultColors[color_which_to_index(colorConstant)];
1306	}
1307}
1308
1309
1310const char*
1311ui_color_name(color_which which)
1312{
1313	// Suppress warnings for B_NO_COLOR.
1314	if (which == B_NO_COLOR)
1315		return NULL;
1316
1317	int32 index = color_which_to_index(which);
1318	if (index < 0 || index >= kColorWhichCount) {
1319		fprintf(stderr, "ui_color_name(): unknown color_which %d\n", which);
1320		return NULL;
1321	}
1322
1323	return kColorNames[index];
1324}
1325
1326
1327color_which
1328which_ui_color(const char* name)
1329{
1330	if (name == NULL)
1331		return B_NO_COLOR;
1332
1333	for (int32 index = 0; index < kColorWhichCount; ++index) {
1334		if (!strcmp(kColorNames[index], name))
1335			return index_to_color_which(index);
1336	}
1337
1338	return B_NO_COLOR;
1339}
1340
1341
1342void
1343set_ui_color(const color_which &which, const rgb_color &color)
1344{
1345	int32 index = color_which_to_index(which);
1346	if (index < 0 || index >= kColorWhichCount) {
1347		fprintf(stderr, "set_ui_color(): unknown color_which %d\n", which);
1348		return;
1349	}
1350
1351	if (ui_color(which) == color)
1352		return;
1353
1354	BPrivate::DesktopLink link;
1355	link.StartMessage(AS_SET_UI_COLOR);
1356	link.Attach<color_which>(which);
1357	link.Attach<rgb_color>(color);
1358	link.Flush();
1359}
1360
1361
1362void
1363set_ui_colors(const BMessage* colors)
1364{
1365	if (colors == NULL)
1366		return;
1367
1368	int32 count = 0;
1369	int32 index = 0;
1370	char* name = NULL;
1371	type_code type;
1372	rgb_color color;
1373	color_which which = B_NO_COLOR;
1374
1375	BPrivate::DesktopLink desktop;
1376	if (desktop.InitCheck() != B_OK)
1377		return;
1378
1379	desktop.StartMessage(AS_SET_UI_COLORS);
1380	desktop.Attach<bool>(false);
1381
1382	// Only colors with names that map to system colors will get through.
1383	while (colors->GetInfo(B_RGB_32_BIT_TYPE, index, &name, &type) == B_OK) {
1384
1385		which = which_ui_color(name);
1386		++index;
1387
1388		if (which == B_NO_COLOR || colors->FindColor(name, &color) != B_OK)
1389			continue;
1390
1391		desktop.Attach<color_which>(which);
1392		desktop.Attach<rgb_color>(color);
1393		++count;
1394	}
1395
1396	if (count == 0)
1397		return;
1398
1399	desktop.Attach<color_which>(B_NO_COLOR);
1400	desktop.Flush();
1401}
1402
1403
1404rgb_color
1405tint_color(rgb_color color, float tint)
1406{
1407	rgb_color result;
1408
1409	#define LIGHTEN(x) ((uint8)(255.0f - (255.0f - x) * tint))
1410	#define DARKEN(x)  ((uint8)(x * (2 - tint)))
1411
1412	if (tint < 1.0f) {
1413		result.red   = LIGHTEN(color.red);
1414		result.green = LIGHTEN(color.green);
1415		result.blue  = LIGHTEN(color.blue);
1416		result.alpha = color.alpha;
1417	} else {
1418		result.red   = DARKEN(color.red);
1419		result.green = DARKEN(color.green);
1420		result.blue  = DARKEN(color.blue);
1421		result.alpha = color.alpha;
1422	}
1423
1424	#undef LIGHTEN
1425	#undef DARKEN
1426
1427	return result;
1428}
1429
1430
1431rgb_color shift_color(rgb_color color, float shift);
1432
1433rgb_color
1434shift_color(rgb_color color, float shift)
1435{
1436	return tint_color(color, shift);
1437}
1438
1439
1440extern "C" status_t
1441_init_interface_kit_()
1442{
1443	status_t status = BPrivate::PaletteConverter::InitializeDefault(true);
1444	if (status < B_OK)
1445		return status;
1446
1447	// init global clipboard
1448	if (be_clipboard == NULL)
1449		be_clipboard = new BClipboard(NULL);
1450
1451	BString path;
1452	if (get_control_look(path) && path.Length() > 0) {
1453		BControlLook* (*instantiate)(image_id);
1454
1455		sControlLookAddon = load_add_on(path.String());
1456		if (sControlLookAddon >= 0
1457			&& get_image_symbol(sControlLookAddon,
1458				"instantiate_control_look",
1459				B_SYMBOL_TYPE_TEXT, (void **)&instantiate) == B_OK) {
1460			be_control_look = instantiate(sControlLookAddon);
1461			if (be_control_look == NULL) {
1462				unload_add_on(sControlLookAddon);
1463				sControlLookAddon = -1;
1464			}
1465		}
1466	}
1467	if (be_control_look == NULL)
1468		be_control_look = new HaikuControlLook();
1469
1470	_init_global_fonts_();
1471
1472	BPrivate::gWidthBuffer = new BPrivate::WidthBuffer;
1473	status = BPrivate::MenuPrivate::CreateBitmaps();
1474	if (status != B_OK)
1475		return status;
1476
1477	_menu_info_ptr_ = &BMenu::sMenuInfo;
1478
1479	status = get_menu_info(&BMenu::sMenuInfo);
1480	if (status != B_OK)
1481		return status;
1482
1483	general_info.background_color = ui_color(B_PANEL_BACKGROUND_COLOR);
1484	general_info.mark_color = ui_color(B_CONTROL_MARK_COLOR);
1485	general_info.highlight_color = ui_color(B_CONTROL_HIGHLIGHT_COLOR);
1486	general_info.window_frame_color = ui_color(B_WINDOW_TAB_COLOR);
1487	general_info.color_frame = true;
1488
1489	// TODO: fill the other static members
1490
1491	return status;
1492}
1493
1494
1495extern "C" status_t
1496_fini_interface_kit_()
1497{
1498	BPrivate::MenuPrivate::DeleteBitmaps();
1499
1500	delete BPrivate::gWidthBuffer;
1501	BPrivate::gWidthBuffer = NULL;
1502
1503	delete be_control_look;
1504	be_control_look = NULL;
1505
1506	// Note: if we ever want to support live switching, we cannot just unload
1507	// the old one since some thread might still be in a method of the object.
1508	// maybe locking/unlocking all loopers around would ensure proper exit.
1509	if (sControlLookAddon >= 0)
1510		unload_add_on(sControlLookAddon);
1511	sControlLookAddon = -1;
1512
1513	// TODO: Anything else?
1514
1515	return B_OK;
1516}
1517
1518
1519
1520namespace BPrivate {
1521
1522
1523/*!	\brief queries the server for the current decorator
1524	\param path BString into which to store current decorator's location
1525	\return boolean true/false
1526*/
1527bool
1528get_decorator(BString& path)
1529{
1530	BPrivate::AppServerLink link;
1531	link.StartMessage(AS_GET_DECORATOR);
1532
1533	int32 code;
1534	if (link.FlushWithReply(code) != B_OK || code != B_OK)
1535		return false;
1536
1537	return link.ReadString(path) == B_OK;
1538}
1539
1540
1541/*!	\brief Private function which sets the window decorator for the system.
1542	\param path BString with the path to the decorator to set
1543
1544	Will return detailed error status via status_t
1545*/
1546status_t
1547set_decorator(const BString& path)
1548{
1549	BPrivate::AppServerLink link;
1550
1551	link.StartMessage(AS_SET_DECORATOR);
1552
1553	link.AttachString(path.String());
1554	link.Flush();
1555
1556	status_t error = B_OK;
1557	link.Read<status_t>(&error);
1558
1559	return error;
1560}
1561
1562
1563/*! \brief sets a window to preview a given decorator
1564	\param path path to any given decorator add-on
1565	\param window pointer to BWindow which will show decorator
1566
1567	Piggy-backs on BWindow::SetDecoratorSettings(...)
1568*/
1569status_t
1570preview_decorator(const BString& path, BWindow* window)
1571{
1572	if (window == NULL)
1573		return B_ERROR;
1574
1575	BMessage msg('prVu');
1576	msg.AddString("preview", path.String());
1577
1578	return window->SetDecoratorSettings(msg);
1579}
1580
1581
1582/*!	\brief queries the server for the current ControlLook path
1583	\param path BString into which to store current ControlLook's add-on path
1584	\return boolean true/false
1585*/
1586bool
1587get_control_look(BString& path)
1588{
1589	BPrivate::AppServerLink link;
1590	link.StartMessage(AS_GET_CONTROL_LOOK);
1591
1592	int32 code;
1593	if (link.FlushWithReply(code) != B_OK || code != B_OK)
1594		return false;
1595
1596	return link.ReadString(path) == B_OK;
1597}
1598
1599
1600/*!	\brief Private function which sets the ControlLook for the system.
1601	\param BString with the ControlLook add-on path to set
1602
1603	Will return detailed error status via status_t
1604*/
1605status_t
1606set_control_look(const BString& path)
1607{
1608	BPrivate::AppServerLink link;
1609
1610	link.StartMessage(AS_SET_CONTROL_LOOK);
1611
1612	link.AttachString(path.String());
1613
1614	status_t error = B_OK;
1615	if (link.FlushWithReply(error) != B_OK)
1616		return B_ERROR;
1617
1618	return error;
1619}
1620
1621
1622status_t
1623get_application_order(int32 workspace, team_id** _applications,
1624	int32* _count)
1625{
1626	BPrivate::AppServerLink link;
1627
1628	link.StartMessage(AS_GET_APPLICATION_ORDER);
1629	link.Attach<int32>(workspace);
1630
1631	int32 code;
1632	status_t status = link.FlushWithReply(code);
1633	if (status != B_OK)
1634		return status;
1635	if (code != B_OK)
1636		return code;
1637
1638	int32 count;
1639	link.Read<int32>(&count);
1640
1641	*_applications = (team_id*)malloc(count * sizeof(team_id));
1642	if (*_applications == NULL)
1643		return B_NO_MEMORY;
1644
1645	link.Read(*_applications, count * sizeof(team_id));
1646	*_count = count;
1647	return B_OK;
1648}
1649
1650
1651status_t
1652get_window_order(int32 workspace, int32** _tokens, int32* _count)
1653{
1654	BPrivate::AppServerLink link;
1655
1656	link.StartMessage(AS_GET_WINDOW_ORDER);
1657	link.Attach<int32>(workspace);
1658
1659	int32 code;
1660	status_t status = link.FlushWithReply(code);
1661	if (status != B_OK)
1662		return status;
1663	if (code != B_OK)
1664		return code;
1665
1666	int32 count;
1667	link.Read<int32>(&count);
1668
1669	*_tokens = (int32*)malloc(count * sizeof(int32));
1670	if (*_tokens == NULL)
1671		return B_NO_MEMORY;
1672
1673	link.Read(*_tokens, count * sizeof(int32));
1674	*_count = count;
1675	return B_OK;
1676}
1677
1678
1679}	// namespace BPrivate
1680
1681// These methods were marked with "Danger, will Robinson!" in
1682// the OpenTracker source, so we might not want to be compatible
1683// here.
1684// In any way, we would need to update Deskbar to use our
1685// replacements, so we could as well just implement them...
1686
1687void
1688do_window_action(int32 windowToken, int32 action, BRect zoomRect, bool zoom)
1689{
1690	BPrivate::AppServerLink link;
1691
1692	link.StartMessage(AS_WINDOW_ACTION);
1693	link.Attach<int32>(windowToken);
1694	link.Attach<int32>(action);
1695		// we don't have any zooming effect
1696
1697	link.Flush();
1698}
1699
1700
1701client_window_info*
1702get_window_info(int32 serverToken)
1703{
1704	BPrivate::AppServerLink link;
1705
1706	link.StartMessage(AS_GET_WINDOW_INFO);
1707	link.Attach<int32>(serverToken);
1708
1709	int32 code;
1710	if (link.FlushWithReply(code) != B_OK || code != B_OK)
1711		return NULL;
1712
1713	int32 size;
1714	link.Read<int32>(&size);
1715
1716	client_window_info* info = (client_window_info*)malloc(size);
1717	if (info == NULL)
1718		return NULL;
1719
1720	link.Read(info, size);
1721	return info;
1722}
1723
1724
1725int32*
1726get_token_list(team_id team, int32* _count)
1727{
1728	BPrivate::AppServerLink link;
1729
1730	link.StartMessage(AS_GET_WINDOW_LIST);
1731	link.Attach<team_id>(team);
1732
1733	int32 code;
1734	if (link.FlushWithReply(code) != B_OK || code != B_OK)
1735		return NULL;
1736
1737	int32 count;
1738	link.Read<int32>(&count);
1739
1740	int32* tokens = (int32*)malloc(count * sizeof(int32));
1741	if (tokens == NULL)
1742		return NULL;
1743
1744	link.Read(tokens, count * sizeof(int32));
1745	*_count = count;
1746	return tokens;
1747}
1748
1749
1750void
1751do_bring_to_front_team(BRect zoomRect, team_id team, bool zoom)
1752{
1753	BPrivate::AppServerLink link;
1754
1755	link.StartMessage(AS_BRING_TEAM_TO_FRONT);
1756	link.Attach<team_id>(team);
1757		// we don't have any zooming effect
1758
1759	link.Flush();
1760}
1761
1762
1763void
1764do_minimize_team(BRect zoomRect, team_id team, bool zoom)
1765{
1766	BPrivate::AppServerLink link;
1767
1768	link.StartMessage(AS_MINIMIZE_TEAM);
1769	link.Attach<team_id>(team);
1770		// we don't have any zooming effect
1771
1772	link.Flush();
1773}
1774
1775
1776//	#pragma mark - truncate string
1777
1778
1779void
1780truncate_string(BString& string, uint32 mode, float width,
1781	const float* escapementArray, float fontSize, float ellipsisWidth,
1782	int32 charCount)
1783{
1784	// add a tiny amount to the width to make floating point inaccuracy
1785	// not drop chars that would actually fit exactly
1786	width += 1.f / 128;
1787
1788	switch (mode) {
1789		case B_TRUNCATE_BEGINNING:
1790		{
1791			float totalWidth = 0;
1792			for (int32 i = charCount - 1; i >= 0; i--) {
1793				float charWidth = escapementArray[i] * fontSize;
1794				if (totalWidth + charWidth > width) {
1795					// we need to truncate
1796					while (totalWidth + ellipsisWidth > width) {
1797						// remove chars until there's enough space for the
1798						// ellipsis
1799						if (++i == charCount) {
1800							// we've reached the end of the string and still
1801							// no space, so return an empty string
1802							string.Truncate(0);
1803							return;
1804						}
1805
1806						totalWidth -= escapementArray[i] * fontSize;
1807					}
1808
1809					string.RemoveChars(0, i + 1);
1810					string.PrependChars(B_UTF8_ELLIPSIS, 1);
1811					return;
1812				}
1813
1814				totalWidth += charWidth;
1815			}
1816
1817			break;
1818		}
1819
1820		case B_TRUNCATE_END:
1821		{
1822			float totalWidth = 0;
1823			for (int32 i = 0; i < charCount; i++) {
1824				float charWidth = escapementArray[i] * fontSize;
1825				if (totalWidth + charWidth > width) {
1826					// we need to truncate
1827					while (totalWidth + ellipsisWidth > width) {
1828						// remove chars until there's enough space for the
1829						// ellipsis
1830						if (i-- == 0) {
1831							// we've reached the start of the string and still
1832							// no space, so return an empty string
1833							string.Truncate(0);
1834							return;
1835						}
1836
1837						totalWidth -= escapementArray[i] * fontSize;
1838					}
1839
1840					string.RemoveChars(i, charCount - i);
1841					string.AppendChars(B_UTF8_ELLIPSIS, 1);
1842					return;
1843				}
1844
1845				totalWidth += charWidth;
1846			}
1847
1848			break;
1849		}
1850
1851		case B_TRUNCATE_MIDDLE:
1852		case B_TRUNCATE_SMART:
1853		{
1854			float leftWidth = 0;
1855			float rightWidth = 0;
1856			int32 leftIndex = 0;
1857			int32 rightIndex = charCount - 1;
1858			bool left = true;
1859
1860			for (int32 i = 0; i < charCount; i++) {
1861				float charWidth
1862					= escapementArray[left ? leftIndex : rightIndex] * fontSize;
1863
1864				if (leftWidth + rightWidth + charWidth > width) {
1865					// we need to truncate
1866					while (leftWidth + rightWidth + ellipsisWidth > width) {
1867						// remove chars until there's enough space for the
1868						// ellipsis
1869						if (leftIndex == 0 && rightIndex == charCount - 1) {
1870							// we've reached both ends of the string and still
1871							// no space, so return an empty string
1872							string.Truncate(0);
1873							return;
1874						}
1875
1876						if (leftIndex > 0 && (rightIndex == charCount - 1
1877								|| leftWidth > rightWidth)) {
1878							// remove char on the left
1879							leftWidth -= escapementArray[--leftIndex]
1880								* fontSize;
1881						} else {
1882							// remove char on the right
1883							rightWidth -= escapementArray[++rightIndex]
1884								* fontSize;
1885						}
1886					}
1887
1888					string.RemoveChars(leftIndex, rightIndex + 1 - leftIndex);
1889					string.InsertChars(B_UTF8_ELLIPSIS, 1, leftIndex);
1890					return;
1891				}
1892
1893				if (left) {
1894					leftIndex++;
1895					leftWidth += charWidth;
1896				} else {
1897					rightIndex--;
1898					rightWidth += charWidth;
1899				}
1900
1901				left = rightWidth > leftWidth;
1902			}
1903
1904			break;
1905		}
1906	}
1907
1908	// we've run through without the need to truncate, leave the string as it is
1909}
1910