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