xref: /haiku/src/kits/interface/InterfaceDefs.cpp (revision cd552c7a15cc10c36dae8d7439ba1d6c0bb168c5)
1 /*
2  * Copyright 2001-2006, 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  */
10 
11 /**	Global functions and variables for the Interface Kit */
12 
13 #include "truncate_string.h"
14 #include "utf8_functions.h"
15 
16 #include <ApplicationPrivate.h>
17 #include <AppServerLink.h>
18 #include <DefaultColors.h>
19 #include <InputServerTypes.h>
20 #include <input_globals.h>
21 #include <ServerProtocol.h>
22 #include <ServerReadOnlyMemory.h>
23 #include <WidthBuffer.h>
24 #include <WindowInfo.h>
25 
26 #include <Font.h>
27 #include <InterfaceDefs.h>
28 #include <Menu.h>
29 #include <Roster.h>
30 #include <ScrollBar.h>
31 #include <Screen.h>
32 #include <String.h>
33 #include <TextView.h>
34 
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 
39 
40 // Private definitions not placed in public headers
41 void _init_global_fonts_();
42 extern "C" status_t _fini_interface_kit_();
43 
44 using namespace BPrivate;
45 
46 // some other weird struct exported by BeOS, it's not initialized, though
47 struct general_ui_info {
48 	rgb_color	background_color;
49 	rgb_color	mark_color;
50 	rgb_color	highlight_color;
51 	bool		color_frame;
52 	rgb_color	window_frame_color;
53 };
54 
55 struct general_ui_info general_info;
56 
57 menu_info *_menu_info_ptr_;
58 
59 extern "C" const char B_NOTIFICATION_SENDER[] = "be:sender";
60 
61 static const rgb_color _kDefaultColors[kNumColors] = {
62 	{216, 216, 216, 255},	// B_PANEL_BACKGROUND_COLOR
63 	{216, 216, 216, 255},	// B_MENU_BACKGROUND_COLOR
64 	{255, 203, 0, 255},		// B_WINDOW_TAB_COLOR
65 	{0, 0, 229, 255},		// B_KEYBOARD_NAVIGATION_COLOR
66 	{51, 102, 152, 255},	// B_DESKTOP_COLOR
67 	{153, 153, 153, 255},	// B_MENU_SELECTED_BACKGROUND_COLOR
68 	{0, 0, 0, 255},			// B_MENU_ITEM_TEXT_COLOR
69 	{0, 0, 0, 255},			// B_MENU_SELECTED_ITEM_TEXT_COLOR
70 	{0, 0, 0, 255},			// B_MENU_SELECTED_BORDER_COLOR
71 	{0, 0, 0, 255},			// B_PANEL_TEXT_COLOR
72 	{255, 255, 255, 255},	// B_DOCUMENT_BACKGROUND_COLOR
73 	{0, 0, 0, 255},			// B_DOCUMENT_TEXT_COLOR
74 	{245, 245, 245, 255},	// B_CONTROL_BACKGROUND_COLOR
75 	{0, 0, 0, 255},			// B_CONTROL_TEXT_COLOR
76 	{0, 0, 0, 255},			// B_CONTROL_BORDER_COLOR
77 	{102, 152, 203, 255},	// B_CONTROL_HIGHLIGHT_COLOR
78 	{0, 0, 0, 255},			// B_NAVIGATION_PULSE_COLOR
79 	{255, 255, 255, 255},	// B_SHINE_COLOR
80 	{0, 0, 0, 255},			// B_SHADOW_COLOR
81 	{255, 255, 0, 255},		// B_TOOLTIP_BACKGROUND_COLOR
82 	{0, 0, 0, 255},			// B_TOOLTIP_TEXT_COLOR
83 	{0, 0, 0, 255},			// B_WINDOW_TEXT_COLOR
84 	{232, 232, 232, 255},	// B_WINDOW_INACTIVE_TAB_COLOR
85 	{80, 80, 80, 255},		// B_WINDOW_INACTIVE_TEXT_COLOR
86 	// 100...
87 	{0, 255, 0, 255},		// B_SUCCESS_COLOR
88 	{255, 0, 0, 255},		// B_FAILURE_COLOR
89 	{}
90 };
91 const rgb_color* BPrivate::kDefaultColors = &_kDefaultColors[0];
92 
93 
94 static status_t
95 mode2parms(uint32 space, uint32 *out_space, int32 *width, int32 *height)
96 {
97 	status_t status = B_OK;
98 
99 	switch (space) {
100 		case B_8_BIT_640x480:
101 			*out_space = B_CMAP8;
102 			*width = 640; *height = 480;
103 			break;
104 		case B_8_BIT_800x600:
105 			*out_space = B_CMAP8;
106 			*width = 800; *height = 600;
107 			break;
108 		case B_8_BIT_1024x768:
109 			*out_space = B_CMAP8;
110 			*width = 1024; *height = 768;
111 			break;
112 		case B_8_BIT_1280x1024:
113 			*out_space = B_CMAP8;
114 			*width = 1280; *height = 1024;
115 			break;
116 		case B_8_BIT_1600x1200:
117 			*out_space = B_CMAP8;
118 			*width = 1600; *height = 1200;
119 			break;
120 		case B_16_BIT_640x480:
121 			*out_space = B_RGB16;
122 			*width = 640; *height = 480;
123 			break;
124 		case B_16_BIT_800x600:
125 			*out_space = B_RGB16;
126 			*width = 800; *height = 600;
127 			break;
128 		case B_16_BIT_1024x768:
129 			*out_space = B_RGB16;
130 			*width = 1024; *height = 768;
131 			break;
132 		case B_16_BIT_1280x1024:
133 			*out_space = B_RGB16;
134 			*width = 1280; *height = 1024;
135 			break;
136 		case B_16_BIT_1600x1200:
137 			*out_space = B_RGB16;
138 			*width = 1600; *height = 1200;
139 			break;
140 		case B_32_BIT_640x480:
141 			*out_space = B_RGB32;
142 			*width = 640; *height = 480;
143 			break;
144 		case B_32_BIT_800x600:
145 			*out_space = B_RGB32;
146 			*width = 800; *height = 600;
147 			break;
148 		case B_32_BIT_1024x768:
149 			*out_space = B_RGB32;
150 			*width = 1024; *height = 768;
151 			break;
152 		case B_32_BIT_1280x1024:
153 			*out_space = B_RGB32;
154 			*width = 1280; *height = 1024;
155 			break;
156 		case B_32_BIT_1600x1200:
157 			*out_space = B_RGB32;
158 			*width = 1600; *height = 1200;
159 			break;
160     		case B_8_BIT_1152x900:
161     			*out_space = B_CMAP8;
162     			*width = 1152; *height = 900;
163     			break;
164     		case B_16_BIT_1152x900:
165     			*out_space = B_RGB16;
166     			*width = 1152; *height = 900;
167     			break;
168     		case B_32_BIT_1152x900:
169     			*out_space = B_RGB32;
170     			*width = 1152; *height = 900;
171     			break;
172 		case B_15_BIT_640x480:
173 			*out_space = B_RGB15;
174 			*width = 640; *height = 480;
175 			break;
176 		case B_15_BIT_800x600:
177 			*out_space = B_RGB15;
178 			*width = 800; *height = 600;
179 			break;
180 		case B_15_BIT_1024x768:
181 			*out_space = B_RGB15;
182 			*width = 1024; *height = 768;
183 			break;
184 		case B_15_BIT_1280x1024:
185 			*out_space = B_RGB15;
186 			*width = 1280; *height = 1024;
187 			break;
188 		case B_15_BIT_1600x1200:
189 			*out_space = B_RGB15;
190 			*width = 1600; *height = 1200;
191 			break;
192     		case B_15_BIT_1152x900:
193     			*out_space = B_RGB15;
194     			*width = 1152; *height = 900;
195     			break;
196     		default:
197     			status = B_BAD_VALUE;
198     			break;
199 	}
200 
201 	return status;
202 }
203 
204 
205 _IMPEXP_BE const color_map *
206 system_colors()
207 {
208 	return BScreen(B_MAIN_SCREEN_ID).ColorMap();
209 }
210 
211 
212 _IMPEXP_BE status_t
213 set_screen_space(int32 index, uint32 space, bool stick)
214 {
215 	int32 width;
216 	int32 height;
217 	uint32 depth;
218 
219 	status_t status = mode2parms(space, &depth, &width, &height);
220 	if (status < B_OK)
221 		return status;
222 
223 	BScreen screen(B_MAIN_SCREEN_ID);
224 	display_mode mode;
225 
226 	// TODO: What about refresh rate ?
227 	// currently we get it from the current video mode, but
228 	// this might be not so wise.
229 	status = screen.GetMode(index, &mode);
230 	if (status < B_OK)
231 		return status;
232 
233 	mode.virtual_width = width;
234 	mode.virtual_height = height;
235 	mode.space = depth;
236 
237 	return screen.SetMode(index, &mode, stick);
238 }
239 
240 
241 _IMPEXP_BE status_t
242 get_scroll_bar_info(scroll_bar_info *info)
243 {
244 	if (info == NULL)
245 		return B_BAD_VALUE;
246 
247 	BPrivate::AppServerLink link;
248 	link.StartMessage(AS_GET_SCROLLBAR_INFO);
249 
250 	int32 code;
251 	if (link.FlushWithReply(code) == B_OK
252 		&& code == B_OK) {
253 		link.Read<scroll_bar_info>(info);
254 		return B_OK;
255 	}
256 
257 	return B_ERROR;
258 }
259 
260 
261 _IMPEXP_BE status_t
262 set_scroll_bar_info(scroll_bar_info *info)
263 {
264 	if (info == NULL)
265 		return B_BAD_VALUE;
266 
267 	BPrivate::AppServerLink link;
268 	int32 code;
269 
270 	link.StartMessage(AS_SET_SCROLLBAR_INFO);
271 	link.Attach<scroll_bar_info>(*info);
272 
273 	if (link.FlushWithReply(code) == B_OK
274 		&& code == B_OK)
275 		return B_OK;
276 
277 	return B_ERROR;
278 }
279 
280 
281 _IMPEXP_BE status_t
282 get_mouse_type(int32 *type)
283 {
284 	BMessage command(IS_GET_MOUSE_TYPE);
285 	BMessage reply;
286 
287 	_control_input_server_(&command, &reply);
288 
289 	if(reply.FindInt32("mouse_type", type) != B_OK)
290 		return B_ERROR;
291 
292 	return B_OK;
293 }
294 
295 
296 _IMPEXP_BE status_t
297 set_mouse_type(int32 type)
298 {
299 	BMessage command(IS_SET_MOUSE_TYPE);
300 	BMessage reply;
301 
302 	command.AddInt32("mouse_type", type);
303 	return _control_input_server_(&command, &reply);
304 }
305 
306 
307 _IMPEXP_BE status_t
308 get_mouse_map(mouse_map *map)
309 {
310 	BMessage command(IS_GET_MOUSE_MAP);
311 	BMessage reply;
312 	const void *data = 0;
313 	ssize_t count;
314 
315 	_control_input_server_(&command, &reply);
316 
317 	if (reply.FindData("mousemap", B_ANY_TYPE, &data, &count) != B_OK)
318 		return B_ERROR;
319 
320 	memcpy(map, data, count);
321 
322 	return B_OK;
323 }
324 
325 
326 _IMPEXP_BE status_t
327 set_mouse_map(mouse_map *map)
328 {
329 	BMessage command(IS_SET_MOUSE_MAP);
330 	BMessage reply;
331 
332 	command.AddData("mousemap", B_ANY_TYPE, map, sizeof(mouse_map));
333 	return _control_input_server_(&command, &reply);
334 }
335 
336 
337 _IMPEXP_BE status_t
338 get_click_speed(bigtime_t *speed)
339 {
340 	BMessage command(IS_GET_CLICK_SPEED);
341 	BMessage reply;
342 
343 	_control_input_server_(&command, &reply);
344 
345 	if (reply.FindInt64("speed", speed) != B_OK)
346 		*speed = 500000;
347 
348 	return B_OK;
349 }
350 
351 
352 _IMPEXP_BE status_t
353 set_click_speed(bigtime_t speed)
354 {
355 	BMessage command(IS_SET_CLICK_SPEED);
356 	BMessage reply;
357 	command.AddInt64("speed", speed);
358 	return _control_input_server_(&command, &reply);
359 }
360 
361 
362 _IMPEXP_BE status_t
363 get_mouse_speed(int32 *speed)
364 {
365 	BMessage command(IS_GET_MOUSE_SPEED);
366 	BMessage reply;
367 
368 	_control_input_server_(&command, &reply);
369 
370 	if (reply.FindInt32("speed", speed) != B_OK)
371 		*speed = 65536;
372 
373 	return B_OK;
374 }
375 
376 
377 _IMPEXP_BE status_t
378 set_mouse_speed(int32 speed)
379 {
380 	BMessage command(IS_SET_MOUSE_SPEED);
381 	BMessage reply;
382 	command.AddInt32("speed", speed);
383 	return _control_input_server_(&command, &reply);
384 }
385 
386 
387 _IMPEXP_BE status_t
388 get_mouse_acceleration(int32 *speed)
389 {
390 	BMessage command(IS_GET_MOUSE_ACCELERATION);
391 	BMessage reply;
392 
393 	_control_input_server_(&command, &reply);
394 
395 	if (reply.FindInt32("speed", speed) != B_OK)
396 		*speed = 65536;
397 
398 	return B_OK;
399 }
400 
401 
402 _IMPEXP_BE status_t
403 set_mouse_acceleration(int32 speed)
404 {
405 	BMessage command(IS_SET_MOUSE_ACCELERATION);
406 	BMessage reply;
407 	command.AddInt32("speed", speed);
408 	return _control_input_server_(&command, &reply);
409 }
410 
411 
412 _IMPEXP_BE status_t
413 get_key_repeat_rate(int32 *rate)
414 {
415 	BMessage command(IS_GET_KEY_REPEAT_RATE);
416 	BMessage reply;
417 
418 	_control_input_server_(&command, &reply);
419 
420 	if (reply.FindInt32("rate", rate) != B_OK)
421 		*rate = 250000;
422 
423 	return B_OK;
424 }
425 
426 
427 _IMPEXP_BE status_t
428 set_key_repeat_rate(int32 rate)
429 {
430 	BMessage command(IS_SET_KEY_REPEAT_RATE);
431 	BMessage reply;
432 	command.AddInt32("rate", rate);
433 	return _control_input_server_(&command, &reply);
434 }
435 
436 
437 _IMPEXP_BE status_t
438 get_key_repeat_delay(bigtime_t *delay)
439 {
440 	BMessage command(IS_GET_KEY_REPEAT_DELAY);
441 	BMessage reply;
442 
443 	_control_input_server_(&command, &reply);
444 
445 	if (reply.FindInt64("delay", delay) != B_OK)
446 		*delay = 200;
447 
448 	return B_OK;
449 }
450 
451 
452 _IMPEXP_BE status_t
453 set_key_repeat_delay(bigtime_t  delay)
454 {
455 	BMessage command(IS_SET_KEY_REPEAT_DELAY);
456 	BMessage reply;
457 	command.AddInt64("delay", delay);
458 	return _control_input_server_(&command, &reply);
459 }
460 
461 
462 _IMPEXP_BE uint32
463 modifiers()
464 {
465 	BMessage command(IS_GET_MODIFIERS);
466 	BMessage reply;
467 	int32 err, modifier;
468 
469 	_control_input_server_(&command, &reply);
470 
471 	if (reply.FindInt32("status", &err) != B_OK)
472 		return 0;
473 
474 	if (reply.FindInt32("modifiers", &modifier) != B_OK)
475 		return 0;
476 
477 	return modifier;
478 }
479 
480 
481 _IMPEXP_BE status_t
482 get_key_info(key_info *info)
483 {
484 	BMessage command(IS_GET_KEY_INFO);
485 	BMessage reply;
486 	const void *data = 0;
487 	int32 err;
488 	ssize_t count;
489 
490 	_control_input_server_(&command, &reply);
491 
492 	if (reply.FindInt32("status", &err) != B_OK)
493 		return B_ERROR;
494 
495 	if (reply.FindData("key_info", B_ANY_TYPE, &data, &count) != B_OK)
496 		return B_ERROR;
497 
498 	memcpy(info, data, count);
499 	return B_OK;
500 }
501 
502 
503 _IMPEXP_BE void
504 get_key_map(key_map **map, char **key_buffer)
505 {
506 	BMessage command(IS_GET_KEY_MAP);
507 	BMessage reply;
508 	ssize_t map_count, key_count;
509 	const void *map_array = 0, *key_array = 0;
510 
511 	_control_input_server_(&command, &reply);
512 
513 	if (reply.FindData("keymap", B_ANY_TYPE, &map_array, &map_count) != B_OK) {
514 		*map = 0; *key_buffer = 0;
515 		return;
516 	}
517 
518 	if (reply.FindData("key_buffer", B_ANY_TYPE, &key_array, &key_count) != B_OK) {
519 		*map = 0; *key_buffer = 0;
520 		return;
521 	}
522 
523 	*map = (key_map *)malloc(map_count);
524 	memcpy(*map, map_array, map_count);
525 	*key_buffer = (char *)malloc(key_count);
526 	memcpy(*key_buffer, key_array, key_count);
527 }
528 
529 
530 _IMPEXP_BE status_t
531 get_keyboard_id(uint16 *id)
532 {
533 	BMessage command(IS_GET_KEYBOARD_ID);
534 	BMessage reply;
535 	uint16 kid;
536 
537 	_control_input_server_(&command, &reply);
538 
539 	reply.FindInt16("id", (int16 *)&kid);
540 	*id = kid;
541 
542 	return B_OK;
543 }
544 
545 
546 _IMPEXP_BE void
547 set_modifier_key(uint32 modifier, uint32 key)
548 {
549 	BMessage command(IS_SET_MODIFIER_KEY);
550 	BMessage reply;
551 
552 	command.AddInt32("modifier", modifier);
553 	command.AddInt32("key", key);
554 	_control_input_server_(&command, &reply);
555 }
556 
557 
558 _IMPEXP_BE void
559 set_keyboard_locks(uint32 modifiers)
560 {
561 	BMessage command(IS_SET_KEYBOARD_LOCKS);
562 	BMessage reply;
563 
564 	command.AddInt32("locks", modifiers);
565 	_control_input_server_(&command, &reply);
566 }
567 
568 
569 _IMPEXP_BE status_t
570 _restore_key_map_()
571 {
572 	BMessage message(IS_RESTORE_KEY_MAP);
573 	BMessage reply;
574 
575 	return _control_input_server_(&message, &reply);
576 }
577 
578 
579 _IMPEXP_BE rgb_color
580 keyboard_navigation_color()
581 {
582 	// Queries the app_server
583 	return ui_color(B_KEYBOARD_NAVIGATION_COLOR);
584 }
585 
586 
587 _IMPEXP_BE int32
588 count_workspaces()
589 {
590 	int32 count = 1;
591 
592 	BPrivate::AppServerLink link;
593 	link.StartMessage(AS_COUNT_WORKSPACES);
594 
595 	status_t status;
596 	if (link.FlushWithReply(status) == B_OK && status == B_OK)
597 		link.Read<int32>(&count);
598 
599 	return count;
600 }
601 
602 
603 _IMPEXP_BE void
604 set_workspace_count(int32 count)
605 {
606 	BPrivate::AppServerLink link;
607 	link.StartMessage(AS_SET_WORKSPACE_COUNT);
608 	link.Attach<int32>(count);
609 	link.Flush();
610 }
611 
612 
613 _IMPEXP_BE int32
614 current_workspace()
615 {
616 	int32 index = 0;
617 
618 	BPrivate::AppServerLink link;
619 	link.StartMessage(AS_CURRENT_WORKSPACE);
620 
621 	int32 status;
622 	if (link.FlushWithReply(status) == B_OK && status == B_OK)
623 		link.Read<int32>(&index);
624 
625 	return index;
626 }
627 
628 
629 _IMPEXP_BE void
630 activate_workspace(int32 workspace)
631 {
632 	BPrivate::AppServerLink link;
633 	link.StartMessage(AS_ACTIVATE_WORKSPACE);
634 	link.Attach<int32>(workspace);
635 	link.Flush();
636 }
637 
638 
639 _IMPEXP_BE bigtime_t
640 idle_time()
641 {
642 	bigtime_t idletime = 0;
643 
644 	BPrivate::AppServerLink link;
645 	link.StartMessage(AS_IDLE_TIME);
646 
647 	int32 code;
648 	if (link.FlushWithReply(code) == B_OK && code == B_OK)
649 		link.Read<int64>(&idletime);
650 
651 	return idletime;
652 }
653 
654 
655 _IMPEXP_BE void
656 run_select_printer_panel()
657 {
658 	// Launches the Printer prefs app via the Roster
659 	be_roster->Launch("application/x-vnd.Be-PRNT");
660 }
661 
662 
663 _IMPEXP_BE void
664 run_add_printer_panel()
665 {
666 	// Launches the Printer prefs app via the Roster and asks it to
667 	// add a printer
668 	// TODO: Implement
669 }
670 
671 
672 _IMPEXP_BE void
673 run_be_about()
674 {
675 	if (be_roster != NULL)
676 		be_roster->Launch("application/x-vnd.haiku-AboutHaiku");
677 }
678 
679 
680 _IMPEXP_BE void
681 set_focus_follows_mouse(bool follow)
682 {
683 	// obviously deprecated API
684 	set_mouse_mode(B_WARP_MOUSE);
685 }
686 
687 
688 _IMPEXP_BE bool
689 focus_follows_mouse()
690 {
691 	return mouse_mode() != B_NORMAL_MOUSE;
692 }
693 
694 
695 _IMPEXP_BE void
696 set_mouse_mode(mode_mouse mode)
697 {
698 	BPrivate::AppServerLink link;
699 	link.StartMessage(AS_SET_MOUSE_MODE);
700 	link.Attach<mode_mouse>(mode);
701 	link.Flush();
702 }
703 
704 
705 _IMPEXP_BE mode_mouse
706 mouse_mode()
707 {
708 	// Gets the focus-follows-mouse style, such as normal, B_WARP_MOUSE, etc.
709 	mode_mouse mode = B_NORMAL_MOUSE;
710 
711 	BPrivate::AppServerLink link;
712 	link.StartMessage(AS_GET_MOUSE_MODE);
713 
714 	int32 code;
715 	if (link.FlushWithReply(code) == B_OK && code == B_OK)
716 		link.Read<mode_mouse>(&mode);
717 
718 	return mode;
719 }
720 
721 
722 _IMPEXP_BE rgb_color
723 ui_color(color_which which)
724 {
725 	int32 index = color_which_to_index(which);
726 	if (index < 0 || index >= kNumColors) {
727 		fprintf(stderr, "ui_color(): unknown color_which %d\n", which);
728 		return make_color(0, 0, 0);
729 	}
730 
731 	if (be_app) {
732 		server_read_only_memory* shared = BApplication::Private::ServerReadOnlyMemory();
733 		return shared->colors[index];
734 	}
735 
736 	return kDefaultColors[index];
737 }
738 
739 
740 _IMPEXP_BE rgb_color
741 tint_color(rgb_color color, float tint)
742 {
743 	rgb_color result;
744 
745 	#define LIGHTEN(x) ((uint8)(255.0f - (255.0f - x) * tint))
746 	#define DARKEN(x)  ((uint8)(x * (2 - tint)))
747 
748 	if (tint < 1.0f) {
749 		result.red   = LIGHTEN(color.red);
750 		result.green = LIGHTEN(color.green);
751 		result.blue  = LIGHTEN(color.blue);
752 		result.alpha = color.alpha;
753 	} else {
754 		result.red   = DARKEN(color.red);
755 		result.green = DARKEN(color.green);
756 		result.blue  = DARKEN(color.blue);
757 		result.alpha = color.alpha;
758 	}
759 
760 	#undef LIGHTEN
761 	#undef DARKEN
762 
763 	return result;
764 }
765 
766 
767 rgb_color shift_color(rgb_color color, float shift);
768 
769 rgb_color
770 shift_color(rgb_color color, float shift)
771 {
772 	return tint_color(color, shift);
773 }
774 
775 
776 extern "C" status_t
777 _init_interface_kit_()
778 {
779 	sem_id widthSem = create_sem(0, "BTextView WidthBuffer Sem");
780 	if (widthSem < 0)
781 		return widthSem;
782 	BTextView::sWidthSem = widthSem;
783 	BTextView::sWidthAtom = 0;
784 	BTextView::sWidths = new _BWidthBuffer_;
785 
786 	_init_global_fonts_();
787 
788 	_menu_info_ptr_ = &BMenu::sMenuInfo;
789 	status_t status = get_menu_info(&BMenu::sMenuInfo);
790 
791 	general_info.background_color = ui_color(B_PANEL_BACKGROUND_COLOR);
792 	general_info.mark_color.set_to(0, 0, 0);
793 	general_info.highlight_color = ui_color(B_CONTROL_HIGHLIGHT_COLOR);
794 	general_info.window_frame_color = ui_color(B_WINDOW_TAB_COLOR);
795 	general_info.color_frame = true;
796 
797 	// TODO: fill the other static members
798 
799 	return status;
800 }
801 
802 
803 extern "C" status_t
804 _fini_interface_kit_()
805 {
806 	//TODO: Implement ?
807 
808 	return B_OK;
809 }
810 
811 
812 //	#pragma mark -
813 
814 
815 /*!
816 	\brief private function used by Deskbar to set window decor
817 	Note, we don't have to be compatible here, and could just change
818 	the Deskbar not to use this anymore
819 	\param theme The theme to choose
820 
821 	- \c 0: BeOS
822 	- \c 1: AmigaOS
823 	- \c 2: Win95
824 	- \c 3: MacOS
825 */
826 void
827 __set_window_decor(int32 theme)
828 {
829 	BPrivate::AppServerLink link;
830 	link.StartMessage(AS_R5_SET_DECORATOR);
831 	link.Attach<int32>(theme);
832 	link.Flush();
833 }
834 
835 
836 namespace BPrivate {
837 
838 /*!
839 	\brief queries the server for the number of available decorators
840 	\return the number of available decorators
841 */
842 int32
843 count_decorators(void)
844 {
845 	BPrivate::AppServerLink link;
846 	link.StartMessage(AS_COUNT_DECORATORS);
847 
848 	int32 code;
849 	int32 count = -1;
850 	if (link.FlushWithReply(code) == B_OK && code == B_OK)
851 		link.Read<int32>(&count);
852 
853 	return count;
854 }
855 
856 /*!
857 	\brief queries the server for the index of the current decorators
858 	\return the current decorator's index
859 
860 	If for some bizarre reason this function fails, it returns -1
861 */
862 int32
863 get_decorator(void)
864 {
865 	BPrivate::AppServerLink link;
866 	link.StartMessage(AS_GET_DECORATOR);
867 
868 	int32 code;
869 	int32 index = -1;
870 	if (link.FlushWithReply(code) == B_OK && code == B_OK)
871 		link.Read<int32>(&index);
872 
873 	return index;
874 }
875 
876 
877 /*!
878 	\brief queries the server for the name of the decorator with a certain index
879 	\param index The index of the decorator to get the name for
880 	\param name BString to receive the name of the decorator
881 	\return B_OK if successful, B_ERROR if not
882 */
883 status_t
884 get_decorator_name(const int32 &index, BString &name)
885 {
886 	BPrivate::AppServerLink link;
887 	link.StartMessage(AS_GET_DECORATOR_NAME);
888 	link.Attach<int32>(index);
889 
890 	int32 code;
891 	if (link.FlushWithReply(code) == B_OK && code == B_OK) {
892 		char *string;
893 		if (link.ReadString(&string) == B_OK) {
894 			name = string;
895 			free(string);
896 			return B_OK;
897 		}
898 	}
899 
900 	return B_ERROR;
901 }
902 
903 /*!
904 	\brief asks the server to draw a decorator preview into a BBitmap
905 	\param index The index of the decorator to get the name for
906 	\param bitmap BBitmap to receive the preview
907 	\return B_OK if successful, B_ERROR if not.
908 
909 	This is currently unimplemented.
910 */
911 status_t
912 get_decorator_preview(const int32 &index, BBitmap *bitmap)
913 {
914 	// TODO: implement get_decorator_preview
915 	return B_ERROR;
916 }
917 
918 
919 /*!
920 	\brief Private function which sets the window decorator for the system.
921 	\param index Index of the decorator to set
922 
923 	If the index is invalid, this function and the server do nothing
924 */
925 status_t
926 set_decorator(const int32 &index)
927 {
928 	if (index < 0)
929 		return B_BAD_VALUE;
930 
931 	BPrivate::AppServerLink link;
932 
933 	link.StartMessage(AS_SET_DECORATOR);
934 	link.Attach<int32>(index);
935 	link.Flush();
936 
937 	return B_OK;
938 }
939 
940 }	// namespace BPrivate
941 
942 // These methods were marked with "Danger, will Robinson!" in
943 // the OpenTracker source, so we might not want to be compatible
944 // here.
945 // In any way, we would need to update Deskbar to use our
946 // replacements, so we could as well just implement them...
947 //
948 // They are defined (also the complete window_info structure) in
949 // src/apps/deskbar/WindowMenuItem.h
950 
951 struct window_info;
952 
953 void do_window_action(int32 window_id, int32 action,
954 		BRect zoomRect, bool zoom);
955 window_info	*get_window_info(int32 a_token);
956 int32 *get_token_list(team_id app, int32 *count);
957 void do_bring_to_front_team(BRect zoomRect, team_id app, bool zoom);
958 void do_minimize_team(BRect zoomRect, team_id team, bool zoom);
959 
960 
961 void
962 do_window_action(int32 windowToken, int32 action,
963 	BRect zoomRect, bool zoom)
964 {
965 	BPrivate::AppServerLink link;
966 
967 	link.StartMessage(AS_WINDOW_ACTION);
968 	link.Attach<int32>(windowToken);
969 	link.Attach<int32>(action);
970 		// we don't have any zooming effect
971 
972 	link.Flush();
973 }
974 
975 
976 window_info	*
977 get_window_info(int32 serverToken)
978 {
979 	BPrivate::AppServerLink link;
980 
981 	link.StartMessage(AS_GET_WINDOW_INFO);
982 	link.Attach<int32>(serverToken);
983 
984 	int32 code;
985 	if (link.FlushWithReply(code) != B_OK || code != B_OK)
986 		return NULL;
987 
988 	int32 size;
989 	link.Read<int32>(&size);
990 
991 	client_window_info* info = (client_window_info*)malloc(size);
992 	if (info == NULL)
993 		return NULL;
994 
995 	link.Read(info, size);
996 	return info;
997 }
998 
999 
1000 int32 *
1001 get_token_list(team_id team, int32 *_count)
1002 {
1003 	BPrivate::AppServerLink link;
1004 
1005 	link.StartMessage(AS_GET_WINDOW_LIST);
1006 	link.Attach<team_id>(team);
1007 
1008 	int32 code;
1009 	if (link.FlushWithReply(code) != B_OK || code != B_OK)
1010 		return NULL;
1011 
1012 	int32 count;
1013 	link.Read<int32>(&count);
1014 
1015 	int32* tokens = (int32*)malloc(count * sizeof(int32));
1016 	if (tokens == NULL)
1017 		return NULL;
1018 
1019 	link.Read(tokens, count * sizeof(int32));
1020 	*_count = count;
1021 	return tokens;
1022 }
1023 
1024 
1025 void
1026 do_bring_to_front_team(BRect zoomRect, team_id team, bool zoom)
1027 {
1028 	BPrivate::AppServerLink link;
1029 
1030 	link.StartMessage(AS_BRING_TEAM_TO_FRONT);
1031 	link.Attach<team_id>(team);
1032 		// we don't have any zooming effect
1033 
1034 	link.Flush();
1035 }
1036 
1037 
1038 void
1039 do_minimize_team(BRect zoomRect, team_id team, bool zoom)
1040 {
1041 	BPrivate::AppServerLink link;
1042 
1043 	link.StartMessage(AS_MINIMIZE_TEAM);
1044 	link.Attach<team_id>(team);
1045 		// we don't have any zooming effect
1046 
1047 	link.Flush();
1048 }
1049 
1050 
1051 //	#pragma mark - truncate string
1052 
1053 
1054 static char*
1055 write_ellipsis(char* dst)
1056 {
1057 	strcpy(dst, B_UTF8_ELLIPSIS);
1058 	// The UTF-8 character spans over 3 bytes
1059 	return dst + 3;
1060 }
1061 
1062 
1063 bool
1064 truncate_end(const char* source, char* dest, uint32 numChars,
1065 	const float* escapementArray, float width, float ellipsisWidth, float size)
1066 {
1067 	float currentWidth = 0.0;
1068 	ellipsisWidth /= size;	// test if this is as accurate as escapementArray * size
1069 	width /= size;
1070 	uint32 lastFit = 0, c;
1071 
1072 	for (c = 0; c < numChars; c++) {
1073 		currentWidth += escapementArray[c];
1074 		if (currentWidth + ellipsisWidth <= width)
1075 			lastFit = c;
1076 
1077 		if (currentWidth > width)
1078 			break;
1079 	}
1080 
1081 	if (c == numChars) {
1082 		// string fits into width
1083 		return false;
1084 	}
1085 
1086 	if (c == 0) {
1087 		// there is no space for the ellipsis
1088 		strcpy(dest, "");
1089 		return true;
1090 	}
1091 
1092 	// copy string to destination
1093 
1094 	for (uint32 i = 0; i < lastFit + 1; i++) {
1095 		// copy one glyph
1096 		do {
1097 			*dest++ = *source++;
1098 		} while (IsInsideGlyph(*source));
1099 	}
1100 
1101 	// write ellipsis and terminate
1102 
1103 	dest = write_ellipsis(dest);
1104 	*dest = '\0';
1105 	return true;
1106 }
1107 
1108 
1109 static char*
1110 copy_from_end(const char* src, char* dst, uint32 numChars, uint32 length,
1111 	const float* escapementArray, float width, float ellipsisWidth, float size)
1112 {
1113 	const char* originalStart = src;
1114 	src += length - 1;
1115 	float currentWidth = 0.0;
1116 	for (int32 c = numChars - 1; c > 0; c--) {
1117 		currentWidth += escapementArray[c] * size;
1118 		if (currentWidth > width) {
1119 			// ups, we definitely don't fit. go back until the ellipsis fits
1120 			currentWidth += ellipsisWidth;
1121 			// go forward again until ellipsis fits (already beyond the target)
1122 			for (uint32 c2 = c; c2 < numChars; c2++) {
1123 //printf(" backward: %c (%ld) (%.1f - %.1f = %.1f)\n", *dst, c2, currentWidth, escapementArray[c2] * size, currentWidth - escapementArray[c2] * size);
1124 				currentWidth -= escapementArray[c2] * size;
1125 				do {
1126 					src++;
1127 				} while (IsInsideGlyph(*src));
1128 				// see if we went back enough
1129 				if (currentWidth <= width)
1130 					break;
1131 			}
1132 			break;
1133 		} else {
1134 			// go back one glyph
1135 			do {
1136 				src--;
1137 			} while (IsInsideGlyph(*src));
1138 		}
1139 	}
1140 	// copy from the end of the string
1141 	uint32 bytesToCopy = originalStart + length - src;
1142 	memcpy(dst, src, bytesToCopy);
1143 	dst += bytesToCopy;
1144 	return dst;
1145 }
1146 
1147 
1148 bool
1149 truncate_middle(const char* source, char* dest, uint32 numChars,
1150 	const float* escapementArray, float width, float ellipsisWidth, float size)
1151 {
1152 	// find visual center
1153 
1154 	ellipsisWidth /= size;	// test if this is as accurate as escapementArray * size
1155 	width /= size;
1156 
1157 	float halfWidth = (width - ellipsisWidth) / 2.0;
1158 	float leftWidth = 0.0, rightWidth = 0.0;
1159 	uint32 left, right;
1160 
1161 	// coming from left...
1162 
1163 	for (left = 0; left < numChars; left++) {
1164 		if (leftWidth + escapementArray[left] > halfWidth)
1165 			break;
1166 
1167 		leftWidth += escapementArray[left];
1168 	}
1169 
1170 	if (left == numChars) {
1171 		// string is smaller than half of the maximum width
1172 		return false;
1173 	}
1174 
1175 	// coming from right...
1176 
1177 	for (right = numChars; right-- > left; ) {
1178 		if (rightWidth + escapementArray[right] > halfWidth)
1179 			break;
1180 
1181 		rightWidth += escapementArray[right];
1182 	}
1183 
1184 	if (left >= right) {
1185 		// string is smaller than the maximum width
1186 		return false;
1187 	}
1188 
1189 	if (left == 0 || right >= numChars - 1) {
1190 		// there is no space for the ellipsis
1191 		strcpy(dest, "");
1192 		return true;
1193 	}
1194 
1195 	// see if the gap between left/right is smaller than the ellipsis
1196 
1197 	float totalWidth = rightWidth + leftWidth;
1198 
1199 	for (uint32 i = left; i < right; i++) {
1200 		totalWidth += escapementArray[i];
1201 		if (totalWidth > width)
1202 			break;
1203 	}
1204 
1205 	if (totalWidth <= width) {
1206 		// the whole string fits!
1207 		return false;
1208 	}
1209 
1210 	// The ellipsis now definitely fits, but let's
1211 	// see if we can add another character
1212 
1213 	totalWidth = ellipsisWidth + rightWidth + leftWidth;
1214 
1215 	if (left > numChars - right) {
1216 		// try right letter first
1217 		if (escapementArray[right] + totalWidth <= width)
1218 			right--;
1219 		else if (escapementArray[left] + totalWidth <= width)
1220 			left++;
1221 	} else {
1222 		// try left letter first
1223 		if (escapementArray[left] + totalWidth <= width)
1224 			left++;
1225 		else if (escapementArray[right] + totalWidth <= width)
1226 			right--;
1227 	}
1228 
1229 	// copy characters
1230 
1231 	for (uint32 i = 0; i < left; i++) {
1232 		// copy one glyph
1233 		do {
1234 			*dest++ = *source++;
1235 		} while (IsInsideGlyph(*source));
1236 	}
1237 
1238 	dest = write_ellipsis(dest);
1239 
1240 	for (uint32 i = left; i < numChars; i++) {
1241 		// copy one glyph
1242 		do {
1243 			if (i >= right)
1244 				*dest++ = *source++;
1245 			else
1246 				source++;
1247 		} while (IsInsideGlyph(*source));
1248 	}
1249 
1250 	// terminate
1251 	dest[0] = '\0';
1252 	return true;
1253 }
1254 
1255 
1256 // ToDo: put into BPrivate namespace
1257 void
1258 truncate_string(const char* string, uint32 mode, float width,
1259 	char* result, const float* escapementArray, float fontSize,
1260 	float ellipsisWidth, int32 length, int32 numChars)
1261 {
1262 	// ToDo: that's actually not correct: the string could be smaller than ellipsisWidth
1263 	if (string == NULL /*|| width < ellipsisWidth*/) {
1264 		// we don't have room for a single glyph
1265 		strcpy(result, "");
1266 		return;
1267 	}
1268 
1269 	// iterate over glyphs and copy source into result string
1270 	// one glyph at a time as long as we have room for the "…" yet
1271 	char* dest = result;
1272 	const char* source = string;
1273 	bool truncated = true;
1274 
1275 	switch (mode) {
1276 		case B_TRUNCATE_BEGINNING: {
1277 			dest = copy_from_end(source, dest, numChars, length,
1278 				escapementArray, width, ellipsisWidth, fontSize);
1279 			// "dst" points to the position behind the last glyph that
1280 			// was copied.
1281 			int32 dist = dest - result;
1282 			// we didn't terminate yet
1283 			*dest = 0;
1284 			if (dist < length) {
1285 				// TODO: Is there a smarter way?
1286 				char* temp = new char[dist + 4];
1287 				char* t = temp;
1288 				// append "…"
1289 				t = write_ellipsis(t);
1290 				// shuffle arround strings so that "…" is prepended
1291 				strcpy(t, result);
1292 				strcpy(result, temp);
1293 				delete[] temp;
1294 /*						char t = result[3];
1295 				memmove(&result[3], result, dist + 1);
1296 				write_ellipsis(result);
1297 				result[3] = t;*/
1298 			}
1299 			break;
1300 		}
1301 
1302 		case B_TRUNCATE_END:
1303 			truncated = truncate_end(source, dest, numChars, escapementArray,
1304 				width, ellipsisWidth, fontSize);
1305 			break;
1306 
1307 		case B_TRUNCATE_SMART:
1308 			// TODO: implement, though it was never implemented on R5
1309 			// FALL THROUGH (at least do something)
1310 		case B_TRUNCATE_MIDDLE:
1311 			truncated = truncate_middle(source, dest, numChars, escapementArray,
1312 				width, ellipsisWidth, fontSize);
1313 			break;
1314 	}
1315 
1316 	if (!truncated) {
1317 		// copy string to destination verbatim
1318 		strlcpy(dest, source, length + 1);
1319 	}
1320 }
1321 
1322