xref: /haiku/src/kits/interface/InterfaceDefs.cpp (revision 6f80a9801fedbe7355c4360bd204ba746ec3ec2d)
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_type(const char* mouse_name, int32 *type)
509 {
510 	BMessage command(IS_GET_MOUSE_TYPE);
511 	BMessage reply;
512 	command.AddString("mouse_name", mouse_name);
513 
514 	status_t err = _control_input_server_(&command, &reply);
515 	if (err != B_OK)
516 		return err;
517 
518 	return reply.FindInt32("mouse_type", type);
519 }
520 
521 
522 status_t
523 set_mouse_type(const char* mouse_name, int32 type)
524 {
525 	BMessage command(IS_SET_MOUSE_TYPE);
526 	BMessage reply;
527 
528 	status_t err_mouse_name = command.AddString("mouse_name", mouse_name);
529 	if (err_mouse_name != B_OK)
530 		return err_mouse_name;
531 
532 	status_t err = command.AddInt32("mouse_type", type);
533 	if (err != B_OK)
534 		return err;
535 	return _control_input_server_(&command, &reply);
536 }
537 
538 
539 status_t
540 get_mouse_map(mouse_map *map)
541 {
542 	BMessage command(IS_GET_MOUSE_MAP);
543 	BMessage reply;
544 	const void *data = 0;
545 	ssize_t count;
546 
547 	status_t err = _control_input_server_(&command, &reply);
548 	if (err == B_OK)
549 		err = reply.FindData("mousemap", B_RAW_TYPE, &data, &count);
550 	if (err != B_OK)
551 		return err;
552 
553 	memcpy(map, data, count);
554 
555 	return B_OK;
556 }
557 
558 
559 status_t
560 set_mouse_map(mouse_map *map)
561 {
562 	BMessage command(IS_SET_MOUSE_MAP);
563 	BMessage reply;
564 
565 	status_t err = command.AddData("mousemap", B_RAW_TYPE, map,
566 		sizeof(mouse_map));
567 	if (err != B_OK)
568 		return err;
569 	return _control_input_server_(&command, &reply);
570 }
571 
572 
573 status_t
574 get_click_speed(bigtime_t *speed)
575 {
576 	BMessage command(IS_GET_CLICK_SPEED);
577 	BMessage reply;
578 
579 	status_t err = _control_input_server_(&command, &reply);
580 	if (err != B_OK)
581 		return err;
582 
583 	if (reply.FindInt64("speed", speed) != B_OK)
584 		*speed = 500000;
585 
586 	return B_OK;
587 }
588 
589 
590 status_t
591 set_click_speed(bigtime_t speed)
592 {
593 	BMessage command(IS_SET_CLICK_SPEED);
594 	BMessage reply;
595 	command.AddInt64("speed", speed);
596 	return _control_input_server_(&command, &reply);
597 }
598 
599 
600 status_t
601 get_mouse_speed(int32 *speed)
602 {
603 	BMessage command(IS_GET_MOUSE_SPEED);
604 	BMessage reply;
605 
606 	status_t err = _control_input_server_(&command, &reply);
607 	if (err != B_OK)
608 		return err;
609 
610 	if (reply.FindInt32("speed", speed) != B_OK)
611 		*speed = 65536;
612 
613 	return B_OK;
614 }
615 
616 
617 status_t
618 set_mouse_speed(int32 speed)
619 {
620 	BMessage command(IS_SET_MOUSE_SPEED);
621 	BMessage reply;
622 	command.AddInt32("speed", speed);
623 	return _control_input_server_(&command, &reply);
624 }
625 
626 
627 status_t
628 get_mouse_speed(const char* mouse_name, int32 *speed)
629 {
630 	BMessage command(IS_GET_MOUSE_SPEED);
631 	BMessage reply;
632 	command.AddString("mouse_name", mouse_name);
633 
634 	status_t err = _control_input_server_(&command, &reply);
635 	if (err != B_OK)
636 		return err;
637 
638 	err = reply.FindInt32("speed", speed);
639 	if (err != B_OK)
640 		return err;
641 
642 	return B_OK;
643 }
644 
645 
646 status_t
647 set_mouse_speed(const char* mouse_name, int32 speed)
648 {
649 	BMessage command(IS_SET_MOUSE_SPEED);
650 	BMessage reply;
651 	command.AddString("mouse_name", mouse_name);
652 
653 	command.AddInt32("speed", speed);
654 
655 	return _control_input_server_(&command, &reply);
656 }
657 
658 
659 status_t
660 get_mouse_acceleration(int32 *speed)
661 {
662 	BMessage command(IS_GET_MOUSE_ACCELERATION);
663 	BMessage reply;
664 
665 	_control_input_server_(&command, &reply);
666 
667 	if (reply.FindInt32("speed", speed) != B_OK)
668 		*speed = 65536;
669 
670 	return B_OK;
671 }
672 
673 
674 status_t
675 set_mouse_acceleration(int32 speed)
676 {
677 	BMessage command(IS_SET_MOUSE_ACCELERATION);
678 	BMessage reply;
679 	command.AddInt32("speed", speed);
680 	return _control_input_server_(&command, &reply);
681 }
682 
683 
684 status_t
685 get_mouse_acceleration(const char* mouse_name, int32 *speed)
686 {
687 	BMessage command(IS_GET_MOUSE_ACCELERATION);
688 	BMessage reply;
689 	command.AddString("mouse_name", mouse_name);
690 
691 	_control_input_server_(&command, &reply);
692 
693 	if (reply.FindInt32("speed", speed) != B_OK)
694 		*speed = 65536;
695 
696 	return B_OK;
697 }
698 
699 
700 status_t
701 set_mouse_acceleration(const char* mouse_name, int32 speed)
702 {
703 	BMessage command(IS_SET_MOUSE_ACCELERATION);
704 	BMessage reply;
705 	command.AddString("mouse_name", mouse_name);
706 
707 	command.AddInt32("speed", speed);
708 
709 	return _control_input_server_(&command, &reply);
710 }
711 
712 
713 status_t
714 get_key_repeat_rate(int32 *rate)
715 {
716 	BMessage command(IS_GET_KEY_REPEAT_RATE);
717 	BMessage reply;
718 
719 	_control_input_server_(&command, &reply);
720 
721 	if (reply.FindInt32("rate", rate) != B_OK)
722 		*rate = 250000;
723 
724 	return B_OK;
725 }
726 
727 
728 status_t
729 set_key_repeat_rate(int32 rate)
730 {
731 	BMessage command(IS_SET_KEY_REPEAT_RATE);
732 	BMessage reply;
733 	command.AddInt32("rate", rate);
734 	return _control_input_server_(&command, &reply);
735 }
736 
737 
738 status_t
739 get_key_repeat_delay(bigtime_t *delay)
740 {
741 	BMessage command(IS_GET_KEY_REPEAT_DELAY);
742 	BMessage reply;
743 
744 	_control_input_server_(&command, &reply);
745 
746 	if (reply.FindInt64("delay", delay) != B_OK)
747 		*delay = 200;
748 
749 	return B_OK;
750 }
751 
752 
753 status_t
754 set_key_repeat_delay(bigtime_t  delay)
755 {
756 	BMessage command(IS_SET_KEY_REPEAT_DELAY);
757 	BMessage reply;
758 	command.AddInt64("delay", delay);
759 	return _control_input_server_(&command, &reply);
760 }
761 
762 
763 uint32
764 modifiers()
765 {
766 	BMessage command(IS_GET_MODIFIERS);
767 	BMessage reply;
768 	int32 err, modifier;
769 
770 	_control_input_server_(&command, &reply);
771 
772 	if (reply.FindInt32("status", &err) != B_OK)
773 		return 0;
774 
775 	if (reply.FindInt32("modifiers", &modifier) != B_OK)
776 		return 0;
777 
778 	return modifier;
779 }
780 
781 
782 status_t
783 get_key_info(key_info *info)
784 {
785 	BMessage command(IS_GET_KEY_INFO);
786 	BMessage reply;
787 	const void *data = 0;
788 	int32 err;
789 	ssize_t count;
790 
791 	_control_input_server_(&command, &reply);
792 
793 	if (reply.FindInt32("status", &err) != B_OK)
794 		return B_ERROR;
795 
796 	if (reply.FindData("key_info", B_ANY_TYPE, &data, &count) != B_OK)
797 		return B_ERROR;
798 
799 	memcpy(info, data, count);
800 	return B_OK;
801 }
802 
803 
804 void
805 get_key_map(key_map **map, char **key_buffer)
806 {
807 	_get_key_map(map, key_buffer, NULL);
808 }
809 
810 
811 void
812 _get_key_map(key_map **map, char **key_buffer, ssize_t *key_buffer_size)
813 {
814 	BMessage command(IS_GET_KEY_MAP);
815 	BMessage reply;
816 	ssize_t map_count, key_count;
817 	const void *map_array = 0, *key_array = 0;
818 	if (key_buffer_size == NULL)
819 		key_buffer_size = &key_count;
820 
821 	_control_input_server_(&command, &reply);
822 
823 	if (reply.FindData("keymap", B_ANY_TYPE, &map_array, &map_count) != B_OK) {
824 		*map = 0; *key_buffer = 0;
825 		return;
826 	}
827 
828 	if (reply.FindData("key_buffer", B_ANY_TYPE, &key_array, key_buffer_size)
829 			!= B_OK) {
830 		*map = 0; *key_buffer = 0;
831 		return;
832 	}
833 
834 	*map = (key_map *)malloc(map_count);
835 	memcpy(*map, map_array, map_count);
836 	*key_buffer = (char *)malloc(*key_buffer_size);
837 	memcpy(*key_buffer, key_array, *key_buffer_size);
838 }
839 
840 
841 status_t
842 get_keyboard_id(uint16 *id)
843 {
844 	BMessage command(IS_GET_KEYBOARD_ID);
845 	BMessage reply;
846 	uint16 kid;
847 
848 	_control_input_server_(&command, &reply);
849 
850 	status_t err = reply.FindInt16("id", (int16 *)&kid);
851 	if (err != B_OK)
852 		return err;
853 	*id = kid;
854 
855 	return B_OK;
856 }
857 
858 
859 status_t
860 get_modifier_key(uint32 modifier, uint32 *key)
861 {
862 	BMessage command(IS_GET_MODIFIER_KEY);
863 	BMessage reply;
864 	uint32 rkey;
865 
866 	command.AddInt32("modifier", modifier);
867 	_control_input_server_(&command, &reply);
868 
869 	status_t err = reply.FindInt32("key", (int32 *) &rkey);
870 	if (err != B_OK)
871 		return err;
872 	*key = rkey;
873 
874 	return B_OK;
875 }
876 
877 
878 void
879 set_modifier_key(uint32 modifier, uint32 key)
880 {
881 	BMessage command(IS_SET_MODIFIER_KEY);
882 	BMessage reply;
883 
884 	command.AddInt32("modifier", modifier);
885 	command.AddInt32("key", key);
886 	_control_input_server_(&command, &reply);
887 }
888 
889 
890 void
891 set_keyboard_locks(uint32 modifiers)
892 {
893 	BMessage command(IS_SET_KEYBOARD_LOCKS);
894 	BMessage reply;
895 
896 	command.AddInt32("locks", modifiers);
897 	_control_input_server_(&command, &reply);
898 }
899 
900 
901 status_t
902 _restore_key_map_()
903 {
904 	BMessage message(IS_RESTORE_KEY_MAP);
905 	BMessage reply;
906 
907 	return _control_input_server_(&message, &reply);
908 }
909 
910 
911 rgb_color
912 keyboard_navigation_color()
913 {
914 	// Queries the app_server
915 	return ui_color(B_KEYBOARD_NAVIGATION_COLOR);
916 }
917 
918 
919 int32
920 count_workspaces()
921 {
922 	uint32 columns;
923 	uint32 rows;
924 	BPrivate::get_workspaces_layout(&columns, &rows);
925 
926 	return columns * rows;
927 }
928 
929 
930 void
931 set_workspace_count(int32 count)
932 {
933 	int32 squareRoot = (int32)sqrt(count);
934 
935 	int32 rows = 1;
936 	for (int32 i = 2; i <= squareRoot; i++) {
937 		if (count % i == 0)
938 			rows = i;
939 	}
940 
941 	int32 columns = count / rows;
942 
943 	BPrivate::set_workspaces_layout(columns, rows);
944 }
945 
946 
947 int32
948 current_workspace()
949 {
950 	int32 index = 0;
951 
952 	BPrivate::AppServerLink link;
953 	link.StartMessage(AS_CURRENT_WORKSPACE);
954 
955 	int32 status;
956 	if (link.FlushWithReply(status) == B_OK && status == B_OK)
957 		link.Read<int32>(&index);
958 
959 	return index;
960 }
961 
962 
963 void
964 activate_workspace(int32 workspace)
965 {
966 	BPrivate::AppServerLink link;
967 	link.StartMessage(AS_ACTIVATE_WORKSPACE);
968 	link.Attach<int32>(workspace);
969 	link.Attach<bool>(false);
970 	link.Flush();
971 }
972 
973 
974 bigtime_t
975 idle_time()
976 {
977 	bigtime_t idletime = 0;
978 
979 	BPrivate::AppServerLink link;
980 	link.StartMessage(AS_IDLE_TIME);
981 
982 	int32 code;
983 	if (link.FlushWithReply(code) == B_OK && code == B_OK)
984 		link.Read<int64>(&idletime);
985 
986 	return idletime;
987 }
988 
989 
990 void
991 run_select_printer_panel()
992 {
993 	if (be_roster == NULL)
994 		return;
995 
996 	// Launches the Printer prefs app via the Roster
997 	be_roster->Launch(PRNT_SIGNATURE_TYPE);
998 }
999 
1000 
1001 void
1002 run_add_printer_panel()
1003 {
1004 	// Launches the Printer prefs app via the Roster and asks it to
1005 	// add a printer
1006 	run_select_printer_panel();
1007 
1008 	BMessenger printerPanelMessenger(PRNT_SIGNATURE_TYPE);
1009 	printerPanelMessenger.SendMessage(PRINTERS_ADD_PRINTER);
1010 }
1011 
1012 
1013 void
1014 run_be_about()
1015 {
1016 	if (be_roster != NULL)
1017 		be_roster->Launch("application/x-vnd.Haiku-About");
1018 }
1019 
1020 
1021 void
1022 set_focus_follows_mouse(bool follow)
1023 {
1024 	// obviously deprecated API
1025 	set_mouse_mode(follow ? B_FOCUS_FOLLOWS_MOUSE : B_NORMAL_MOUSE);
1026 }
1027 
1028 
1029 bool
1030 focus_follows_mouse()
1031 {
1032 	return mouse_mode() == B_FOCUS_FOLLOWS_MOUSE;
1033 }
1034 
1035 
1036 void
1037 set_mouse_mode(mode_mouse mode)
1038 {
1039 	BPrivate::AppServerLink link;
1040 	link.StartMessage(AS_SET_MOUSE_MODE);
1041 	link.Attach<mode_mouse>(mode);
1042 	link.Flush();
1043 }
1044 
1045 
1046 mode_mouse
1047 mouse_mode()
1048 {
1049 	// Gets the mouse focus style, such as activate to click,
1050 	// focus to click, ...
1051 	mode_mouse mode = B_NORMAL_MOUSE;
1052 
1053 	BPrivate::AppServerLink link;
1054 	link.StartMessage(AS_GET_MOUSE_MODE);
1055 
1056 	int32 code;
1057 	if (link.FlushWithReply(code) == B_OK && code == B_OK)
1058 		link.Read<mode_mouse>(&mode);
1059 
1060 	return mode;
1061 }
1062 
1063 
1064 void
1065 set_focus_follows_mouse_mode(mode_focus_follows_mouse mode)
1066 {
1067 	BPrivate::AppServerLink link;
1068 	link.StartMessage(AS_SET_FOCUS_FOLLOWS_MOUSE_MODE);
1069 	link.Attach<mode_focus_follows_mouse>(mode);
1070 	link.Flush();
1071 }
1072 
1073 
1074 mode_focus_follows_mouse
1075 focus_follows_mouse_mode()
1076 {
1077 	mode_focus_follows_mouse mode = B_NORMAL_FOCUS_FOLLOWS_MOUSE;
1078 
1079 	BPrivate::AppServerLink link;
1080 	link.StartMessage(AS_GET_FOCUS_FOLLOWS_MOUSE_MODE);
1081 
1082 	int32 code;
1083 	if (link.FlushWithReply(code) == B_OK && code == B_OK)
1084 		link.Read<mode_focus_follows_mouse>(&mode);
1085 
1086 	return mode;
1087 }
1088 
1089 
1090 status_t
1091 get_mouse(BPoint* screenWhere, uint32* buttons)
1092 {
1093 	if (screenWhere == NULL && buttons == NULL)
1094 		return B_BAD_VALUE;
1095 
1096 	BPrivate::AppServerLink link;
1097 	link.StartMessage(AS_GET_CURSOR_POSITION);
1098 
1099 	int32 code;
1100 	status_t ret = link.FlushWithReply(code);
1101 	if (ret != B_OK)
1102 		return ret;
1103 	if (code != B_OK)
1104 		return code;
1105 
1106 	if (screenWhere != NULL)
1107 		ret = link.Read<BPoint>(screenWhere);
1108 	else {
1109 		BPoint dummy;
1110 		ret = link.Read<BPoint>(&dummy);
1111 	}
1112 	if (ret != B_OK)
1113 		return ret;
1114 
1115 	if (buttons != NULL)
1116 		ret = link.Read<uint32>(buttons);
1117 	else {
1118 		uint32 dummy;
1119 		ret = link.Read<uint32>(&dummy);
1120 	}
1121 
1122 	return ret;
1123 }
1124 
1125 
1126 status_t
1127 get_mouse_bitmap(BBitmap** bitmap, BPoint* hotspot)
1128 {
1129 	if (bitmap == NULL && hotspot == NULL)
1130 		return B_BAD_VALUE;
1131 
1132 	BPrivate::AppServerLink link;
1133 	link.StartMessage(AS_GET_CURSOR_BITMAP);
1134 
1135 	int32 code;
1136 	status_t status = link.FlushWithReply(code);
1137 	if (status != B_OK)
1138 		return status;
1139 	if (code != B_OK)
1140 		return code;
1141 
1142 	uint32 size = 0;
1143 	uint32 cursorWidth = 0;
1144 	uint32 cursorHeight = 0;
1145 	color_space colorspace = B_RGBA32;
1146 
1147 	// if link.Read() returns an error, the same error will be returned on
1148 	// subsequent calls, so we'll check only the return value of the last call
1149 	link.Read<uint32>(&size);
1150 	link.Read<uint32>(&cursorWidth);
1151 	link.Read<uint32>(&cursorHeight);
1152 	link.Read<color_space>(&colorspace);
1153 	if (hotspot == NULL) {
1154 		BPoint dummy;
1155 		link.Read<BPoint>(&dummy);
1156 	} else
1157 		link.Read<BPoint>(hotspot);
1158 
1159 	void* data = NULL;
1160 	if (size > 0)
1161 		data = malloc(size);
1162 	if (data == NULL)
1163 		return B_NO_MEMORY;
1164 
1165 	status = link.Read(data, size);
1166 	if (status != B_OK) {
1167 		free(data);
1168 		return status;
1169 	}
1170 
1171 	BBitmap* cursorBitmap = new (std::nothrow) BBitmap(BRect(0, 0,
1172 		cursorWidth - 1, cursorHeight - 1), colorspace);
1173 
1174 	if (cursorBitmap == NULL) {
1175 		free(data);
1176 		return B_NO_MEMORY;
1177 	}
1178 	status = cursorBitmap->InitCheck();
1179 	if (status == B_OK)
1180 		cursorBitmap->SetBits(data, size, 0, colorspace);
1181 
1182 	free(data);
1183 
1184 	if (status == B_OK && bitmap != NULL)
1185 		*bitmap = cursorBitmap;
1186 	else
1187 		delete cursorBitmap;
1188 
1189 	return status;
1190 }
1191 
1192 
1193 void
1194 set_accept_first_click(bool acceptFirstClick)
1195 {
1196 	BPrivate::AppServerLink link;
1197 	link.StartMessage(AS_SET_ACCEPT_FIRST_CLICK);
1198 	link.Attach<bool>(acceptFirstClick);
1199 	link.Flush();
1200 }
1201 
1202 
1203 bool
1204 accept_first_click()
1205 {
1206 	// Gets the accept first click status
1207 	bool acceptFirstClick = true;
1208 
1209 	BPrivate::AppServerLink link;
1210 	link.StartMessage(AS_GET_ACCEPT_FIRST_CLICK);
1211 
1212 	int32 code;
1213 	if (link.FlushWithReply(code) == B_OK && code == B_OK)
1214 		link.Read<bool>(&acceptFirstClick);
1215 
1216 	return acceptFirstClick;
1217 }
1218 
1219 
1220 rgb_color
1221 ui_color(color_which which)
1222 {
1223 	int32 index = color_which_to_index(which);
1224 	if (index < 0 || index >= kColorWhichCount) {
1225 		fprintf(stderr, "ui_color(): unknown color_which %d\n", which);
1226 		return make_color(0, 0, 0);
1227 	}
1228 
1229 	if (be_app != NULL) {
1230 		server_read_only_memory* shared
1231 			= BApplication::Private::ServerReadOnlyMemory();
1232 		if (shared != NULL) {
1233 			// check for unset colors
1234 			if (shared->colors[index] == B_TRANSPARENT_COLOR)
1235 				shared->colors[index] = kDefaultColors[index];
1236 
1237 			return shared->colors[index];
1238 		}
1239 	}
1240 
1241 	return kDefaultColors[index];
1242 }
1243 
1244 
1245 const char*
1246 ui_color_name(color_which which)
1247 {
1248 	// Suppress warnings for B_NO_COLOR.
1249 	if (which == B_NO_COLOR)
1250 		return NULL;
1251 
1252 	int32 index = color_which_to_index(which);
1253 	if (index < 0 || index >= kColorWhichCount) {
1254 		fprintf(stderr, "ui_color_name(): unknown color_which %d\n", which);
1255 		return NULL;
1256 	}
1257 
1258 	return kColorNames[index];
1259 }
1260 
1261 
1262 color_which
1263 which_ui_color(const char* name)
1264 {
1265 	if (name == NULL)
1266 		return B_NO_COLOR;
1267 
1268 	for (int32 index = 0; index < kColorWhichCount; ++index) {
1269 		if (!strcmp(kColorNames[index], name))
1270 			return index_to_color_which(index);
1271 	}
1272 
1273 	return B_NO_COLOR;
1274 }
1275 
1276 
1277 void
1278 set_ui_color(const color_which &which, const rgb_color &color)
1279 {
1280 	int32 index = color_which_to_index(which);
1281 	if (index < 0 || index >= kColorWhichCount) {
1282 		fprintf(stderr, "set_ui_color(): unknown color_which %d\n", which);
1283 		return;
1284 	}
1285 
1286 	if (ui_color(which) == color)
1287 		return;
1288 
1289 	BPrivate::DesktopLink link;
1290 	link.StartMessage(AS_SET_UI_COLOR);
1291 	link.Attach<color_which>(which);
1292 	link.Attach<rgb_color>(color);
1293 	link.Flush();
1294 }
1295 
1296 
1297 void
1298 set_ui_colors(const BMessage* colors)
1299 {
1300 	if (colors == NULL)
1301 		return;
1302 
1303 	int32 count = 0;
1304 	int32 index = 0;
1305 	char* name = NULL;
1306 	type_code type;
1307 	rgb_color color;
1308 	color_which which = B_NO_COLOR;
1309 
1310 	BPrivate::DesktopLink desktop;
1311 	if (desktop.InitCheck() != B_OK)
1312 		return;
1313 
1314 	desktop.StartMessage(AS_SET_UI_COLORS);
1315 	desktop.Attach<bool>(false);
1316 
1317 	// Only colors with names that map to system colors will get through.
1318 	while (colors->GetInfo(B_RGB_32_BIT_TYPE, index, &name, &type) == B_OK) {
1319 
1320 		which = which_ui_color(name);
1321 		++index;
1322 
1323 		if (which == B_NO_COLOR || colors->FindColor(name, &color) != B_OK)
1324 			continue;
1325 
1326 		desktop.Attach<color_which>(which);
1327 		desktop.Attach<rgb_color>(color);
1328 		++count;
1329 	}
1330 
1331 	if (count == 0)
1332 		return;
1333 
1334 	desktop.Attach<color_which>(B_NO_COLOR);
1335 	desktop.Flush();
1336 }
1337 
1338 
1339 rgb_color
1340 tint_color(rgb_color color, float tint)
1341 {
1342 	rgb_color result;
1343 
1344 	#define LIGHTEN(x) ((uint8)(255.0f - (255.0f - x) * tint))
1345 	#define DARKEN(x)  ((uint8)(x * (2 - tint)))
1346 
1347 	if (tint < 1.0f) {
1348 		result.red   = LIGHTEN(color.red);
1349 		result.green = LIGHTEN(color.green);
1350 		result.blue  = LIGHTEN(color.blue);
1351 		result.alpha = color.alpha;
1352 	} else {
1353 		result.red   = DARKEN(color.red);
1354 		result.green = DARKEN(color.green);
1355 		result.blue  = DARKEN(color.blue);
1356 		result.alpha = color.alpha;
1357 	}
1358 
1359 	#undef LIGHTEN
1360 	#undef DARKEN
1361 
1362 	return result;
1363 }
1364 
1365 
1366 rgb_color shift_color(rgb_color color, float shift);
1367 
1368 rgb_color
1369 shift_color(rgb_color color, float shift)
1370 {
1371 	return tint_color(color, shift);
1372 }
1373 
1374 
1375 extern "C" status_t
1376 _init_interface_kit_()
1377 {
1378 	status_t status = BPrivate::PaletteConverter::InitializeDefault(true);
1379 	if (status < B_OK)
1380 		return status;
1381 
1382 	// init global clipboard
1383 	if (be_clipboard == NULL)
1384 		be_clipboard = new BClipboard(NULL);
1385 
1386 	BString path;
1387 	if (get_control_look(path) && path.Length() > 0) {
1388 		BControlLook* (*instantiate)(image_id);
1389 
1390 		sControlLookAddon = load_add_on(path.String());
1391 		if (sControlLookAddon >= 0
1392 			&& get_image_symbol(sControlLookAddon,
1393 				"instantiate_control_look",
1394 				B_SYMBOL_TYPE_TEXT, (void **)&instantiate) == B_OK) {
1395 			be_control_look = instantiate(sControlLookAddon);
1396 			if (be_control_look == NULL) {
1397 				unload_add_on(sControlLookAddon);
1398 				sControlLookAddon = -1;
1399 			}
1400 		}
1401 	}
1402 	if (be_control_look == NULL)
1403 		be_control_look = new HaikuControlLook();
1404 
1405 	_init_global_fonts_();
1406 
1407 	BPrivate::gWidthBuffer = new BPrivate::WidthBuffer;
1408 	status = BPrivate::MenuPrivate::CreateBitmaps();
1409 	if (status != B_OK)
1410 		return status;
1411 
1412 	_menu_info_ptr_ = &BMenu::sMenuInfo;
1413 
1414 	status = get_menu_info(&BMenu::sMenuInfo);
1415 	if (status != B_OK)
1416 		return status;
1417 
1418 	general_info.background_color = ui_color(B_PANEL_BACKGROUND_COLOR);
1419 	general_info.mark_color = ui_color(B_CONTROL_MARK_COLOR);
1420 	general_info.highlight_color = ui_color(B_CONTROL_HIGHLIGHT_COLOR);
1421 	general_info.window_frame_color = ui_color(B_WINDOW_TAB_COLOR);
1422 	general_info.color_frame = true;
1423 
1424 	// TODO: fill the other static members
1425 
1426 	return status;
1427 }
1428 
1429 
1430 extern "C" status_t
1431 _fini_interface_kit_()
1432 {
1433 	BPrivate::MenuPrivate::DeleteBitmaps();
1434 
1435 	delete BPrivate::gWidthBuffer;
1436 	BPrivate::gWidthBuffer = NULL;
1437 
1438 	delete be_control_look;
1439 	be_control_look = NULL;
1440 
1441 	// Note: if we ever want to support live switching, we cannot just unload
1442 	// the old one since some thread might still be in a method of the object.
1443 	// maybe locking/unlocking all loopers around would ensure proper exit.
1444 	if (sControlLookAddon >= 0)
1445 		unload_add_on(sControlLookAddon);
1446 	sControlLookAddon = -1;
1447 
1448 	// TODO: Anything else?
1449 
1450 	return B_OK;
1451 }
1452 
1453 
1454 
1455 namespace BPrivate {
1456 
1457 
1458 /*!	\brief queries the server for the current decorator
1459 	\param path BString into which to store current decorator's location
1460 	\return boolean true/false
1461 */
1462 bool
1463 get_decorator(BString& path)
1464 {
1465 	BPrivate::AppServerLink link;
1466 	link.StartMessage(AS_GET_DECORATOR);
1467 
1468 	int32 code;
1469 	if (link.FlushWithReply(code) != B_OK || code != B_OK)
1470 		return false;
1471 
1472 	return link.ReadString(path) == B_OK;
1473 }
1474 
1475 
1476 /*!	\brief Private function which sets the window decorator for the system.
1477 	\param path BString with the path to the decorator to set
1478 
1479 	Will return detailed error status via status_t
1480 */
1481 status_t
1482 set_decorator(const BString& path)
1483 {
1484 	BPrivate::AppServerLink link;
1485 
1486 	link.StartMessage(AS_SET_DECORATOR);
1487 
1488 	link.AttachString(path.String());
1489 	link.Flush();
1490 
1491 	status_t error = B_OK;
1492 	link.Read<status_t>(&error);
1493 
1494 	return error;
1495 }
1496 
1497 
1498 /*! \brief sets a window to preview a given decorator
1499 	\param path path to any given decorator add-on
1500 	\param window pointer to BWindow which will show decorator
1501 
1502 	Piggy-backs on BWindow::SetDecoratorSettings(...)
1503 */
1504 status_t
1505 preview_decorator(const BString& path, BWindow* window)
1506 {
1507 	if (window == NULL)
1508 		return B_ERROR;
1509 
1510 	BMessage msg('prVu');
1511 	msg.AddString("preview", path.String());
1512 
1513 	return window->SetDecoratorSettings(msg);
1514 }
1515 
1516 
1517 /*!	\brief queries the server for the current ControlLook path
1518 	\param path BString into which to store current ControlLook's add-on path
1519 	\return boolean true/false
1520 */
1521 bool
1522 get_control_look(BString& path)
1523 {
1524 	BPrivate::AppServerLink link;
1525 	link.StartMessage(AS_GET_CONTROL_LOOK);
1526 
1527 	int32 code;
1528 	if (link.FlushWithReply(code) != B_OK || code != B_OK)
1529 		return false;
1530 
1531 	return link.ReadString(path) == B_OK;
1532 }
1533 
1534 
1535 /*!	\brief Private function which sets the ControlLook for the system.
1536 	\param BString with the ControlLook add-on path to set
1537 
1538 	Will return detailed error status via status_t
1539 */
1540 status_t
1541 set_control_look(const BString& path)
1542 {
1543 	BPrivate::AppServerLink link;
1544 
1545 	link.StartMessage(AS_SET_CONTROL_LOOK);
1546 
1547 	link.AttachString(path.String());
1548 
1549 	status_t error = B_OK;
1550 	if (link.FlushWithReply(error) != B_OK)
1551 		return B_ERROR;
1552 
1553 	return error;
1554 }
1555 
1556 
1557 status_t
1558 get_application_order(int32 workspace, team_id** _applications,
1559 	int32* _count)
1560 {
1561 	BPrivate::AppServerLink link;
1562 
1563 	link.StartMessage(AS_GET_APPLICATION_ORDER);
1564 	link.Attach<int32>(workspace);
1565 
1566 	int32 code;
1567 	status_t status = link.FlushWithReply(code);
1568 	if (status != B_OK)
1569 		return status;
1570 	if (code != B_OK)
1571 		return code;
1572 
1573 	int32 count;
1574 	link.Read<int32>(&count);
1575 
1576 	*_applications = (team_id*)malloc(count * sizeof(team_id));
1577 	if (*_applications == NULL)
1578 		return B_NO_MEMORY;
1579 
1580 	link.Read(*_applications, count * sizeof(team_id));
1581 	*_count = count;
1582 	return B_OK;
1583 }
1584 
1585 
1586 status_t
1587 get_window_order(int32 workspace, int32** _tokens, int32* _count)
1588 {
1589 	BPrivate::AppServerLink link;
1590 
1591 	link.StartMessage(AS_GET_WINDOW_ORDER);
1592 	link.Attach<int32>(workspace);
1593 
1594 	int32 code;
1595 	status_t status = link.FlushWithReply(code);
1596 	if (status != B_OK)
1597 		return status;
1598 	if (code != B_OK)
1599 		return code;
1600 
1601 	int32 count;
1602 	link.Read<int32>(&count);
1603 
1604 	*_tokens = (int32*)malloc(count * sizeof(int32));
1605 	if (*_tokens == NULL)
1606 		return B_NO_MEMORY;
1607 
1608 	link.Read(*_tokens, count * sizeof(int32));
1609 	*_count = count;
1610 	return B_OK;
1611 }
1612 
1613 
1614 }	// namespace BPrivate
1615 
1616 // These methods were marked with "Danger, will Robinson!" in
1617 // the OpenTracker source, so we might not want to be compatible
1618 // here.
1619 // In any way, we would need to update Deskbar to use our
1620 // replacements, so we could as well just implement them...
1621 
1622 void
1623 do_window_action(int32 windowToken, int32 action, BRect zoomRect, bool zoom)
1624 {
1625 	BPrivate::AppServerLink link;
1626 
1627 	link.StartMessage(AS_WINDOW_ACTION);
1628 	link.Attach<int32>(windowToken);
1629 	link.Attach<int32>(action);
1630 		// we don't have any zooming effect
1631 
1632 	link.Flush();
1633 }
1634 
1635 
1636 client_window_info*
1637 get_window_info(int32 serverToken)
1638 {
1639 	BPrivate::AppServerLink link;
1640 
1641 	link.StartMessage(AS_GET_WINDOW_INFO);
1642 	link.Attach<int32>(serverToken);
1643 
1644 	int32 code;
1645 	if (link.FlushWithReply(code) != B_OK || code != B_OK)
1646 		return NULL;
1647 
1648 	int32 size;
1649 	link.Read<int32>(&size);
1650 
1651 	client_window_info* info = (client_window_info*)malloc(size);
1652 	if (info == NULL)
1653 		return NULL;
1654 
1655 	link.Read(info, size);
1656 	return info;
1657 }
1658 
1659 
1660 int32*
1661 get_token_list(team_id team, int32* _count)
1662 {
1663 	BPrivate::AppServerLink link;
1664 
1665 	link.StartMessage(AS_GET_WINDOW_LIST);
1666 	link.Attach<team_id>(team);
1667 
1668 	int32 code;
1669 	if (link.FlushWithReply(code) != B_OK || code != B_OK)
1670 		return NULL;
1671 
1672 	int32 count;
1673 	link.Read<int32>(&count);
1674 
1675 	int32* tokens = (int32*)malloc(count * sizeof(int32));
1676 	if (tokens == NULL)
1677 		return NULL;
1678 
1679 	link.Read(tokens, count * sizeof(int32));
1680 	*_count = count;
1681 	return tokens;
1682 }
1683 
1684 
1685 void
1686 do_bring_to_front_team(BRect zoomRect, team_id team, bool zoom)
1687 {
1688 	BPrivate::AppServerLink link;
1689 
1690 	link.StartMessage(AS_BRING_TEAM_TO_FRONT);
1691 	link.Attach<team_id>(team);
1692 		// we don't have any zooming effect
1693 
1694 	link.Flush();
1695 }
1696 
1697 
1698 void
1699 do_minimize_team(BRect zoomRect, team_id team, bool zoom)
1700 {
1701 	BPrivate::AppServerLink link;
1702 
1703 	link.StartMessage(AS_MINIMIZE_TEAM);
1704 	link.Attach<team_id>(team);
1705 		// we don't have any zooming effect
1706 
1707 	link.Flush();
1708 }
1709 
1710 
1711 //	#pragma mark - truncate string
1712 
1713 
1714 void
1715 truncate_string(BString& string, uint32 mode, float width,
1716 	const float* escapementArray, float fontSize, float ellipsisWidth,
1717 	int32 charCount)
1718 {
1719 	// add a tiny amount to the width to make floating point inaccuracy
1720 	// not drop chars that would actually fit exactly
1721 	width += 1.f / 128;
1722 
1723 	switch (mode) {
1724 		case B_TRUNCATE_BEGINNING:
1725 		{
1726 			float totalWidth = 0;
1727 			for (int32 i = charCount - 1; i >= 0; i--) {
1728 				float charWidth = escapementArray[i] * fontSize;
1729 				if (totalWidth + charWidth > width) {
1730 					// we need to truncate
1731 					while (totalWidth + ellipsisWidth > width) {
1732 						// remove chars until there's enough space for the
1733 						// ellipsis
1734 						if (++i == charCount) {
1735 							// we've reached the end of the string and still
1736 							// no space, so return an empty string
1737 							string.Truncate(0);
1738 							return;
1739 						}
1740 
1741 						totalWidth -= escapementArray[i] * fontSize;
1742 					}
1743 
1744 					string.RemoveChars(0, i + 1);
1745 					string.PrependChars(B_UTF8_ELLIPSIS, 1);
1746 					return;
1747 				}
1748 
1749 				totalWidth += charWidth;
1750 			}
1751 
1752 			break;
1753 		}
1754 
1755 		case B_TRUNCATE_END:
1756 		{
1757 			float totalWidth = 0;
1758 			for (int32 i = 0; i < charCount; i++) {
1759 				float charWidth = escapementArray[i] * fontSize;
1760 				if (totalWidth + charWidth > width) {
1761 					// we need to truncate
1762 					while (totalWidth + ellipsisWidth > width) {
1763 						// remove chars until there's enough space for the
1764 						// ellipsis
1765 						if (i-- == 0) {
1766 							// we've reached the start of the string and still
1767 							// no space, so return an empty string
1768 							string.Truncate(0);
1769 							return;
1770 						}
1771 
1772 						totalWidth -= escapementArray[i] * fontSize;
1773 					}
1774 
1775 					string.RemoveChars(i, charCount - i);
1776 					string.AppendChars(B_UTF8_ELLIPSIS, 1);
1777 					return;
1778 				}
1779 
1780 				totalWidth += charWidth;
1781 			}
1782 
1783 			break;
1784 		}
1785 
1786 		case B_TRUNCATE_MIDDLE:
1787 		case B_TRUNCATE_SMART:
1788 		{
1789 			float leftWidth = 0;
1790 			float rightWidth = 0;
1791 			int32 leftIndex = 0;
1792 			int32 rightIndex = charCount - 1;
1793 			bool left = true;
1794 
1795 			for (int32 i = 0; i < charCount; i++) {
1796 				float charWidth
1797 					= escapementArray[left ? leftIndex : rightIndex] * fontSize;
1798 
1799 				if (leftWidth + rightWidth + charWidth > width) {
1800 					// we need to truncate
1801 					while (leftWidth + rightWidth + ellipsisWidth > width) {
1802 						// remove chars until there's enough space for the
1803 						// ellipsis
1804 						if (leftIndex == 0 && rightIndex == charCount - 1) {
1805 							// we've reached both ends of the string and still
1806 							// no space, so return an empty string
1807 							string.Truncate(0);
1808 							return;
1809 						}
1810 
1811 						if (leftIndex > 0 && (rightIndex == charCount - 1
1812 								|| leftWidth > rightWidth)) {
1813 							// remove char on the left
1814 							leftWidth -= escapementArray[--leftIndex]
1815 								* fontSize;
1816 						} else {
1817 							// remove char on the right
1818 							rightWidth -= escapementArray[++rightIndex]
1819 								* fontSize;
1820 						}
1821 					}
1822 
1823 					string.RemoveChars(leftIndex, rightIndex + 1 - leftIndex);
1824 					string.InsertChars(B_UTF8_ELLIPSIS, 1, leftIndex);
1825 					return;
1826 				}
1827 
1828 				if (left) {
1829 					leftIndex++;
1830 					leftWidth += charWidth;
1831 				} else {
1832 					rightIndex--;
1833 					rightWidth += charWidth;
1834 				}
1835 
1836 				left = rightWidth > leftWidth;
1837 			}
1838 
1839 			break;
1840 		}
1841 	}
1842 
1843 	// we've run through without the need to truncate, leave the string as it is
1844 }
1845