/* DecView.cpp: The Appearance app's decorator handler Utilizes app_server graphics module emulation to allows decorators to display a preview. Saves the chosen decorator's path in a settings file in the app_server settings directory. */ #include #include #include #include #include #include "DecView.h" #include "PortLink.h" #include #include #include #include "RGBColor.h" #include "defs.h" #include "PreviewDriver.h" #include "Decorator.h" #define DEBUG_DECORATOR DecView::DecView(BRect frame, const char *name, int32 resize, int32 flags) :BView(frame,name,resize,flags) { SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); // Set up list of color attributes declist=new BListView(BRect(10,10,110,110),"DecoratorList"); scrollview=new BScrollView("ScrollView",declist, B_FOLLOW_LEFT | B_FOLLOW_TOP, 0, false, true); AddChild(scrollview); scrollview->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR)); declist->SetSelectionMessage(new BMessage(DECORATOR_CHOSEN)); BRect cvrect(0,0,50,25); cvrect.OffsetTo(Bounds().right-60, scrollview->Frame().top); apply=new BButton(cvrect,"ApplyButton","Apply", new BMessage(APPLY_SETTINGS),B_FOLLOW_LEFT |B_FOLLOW_TOP, B_WILL_DRAW | B_NAVIGABLE); AddChild(apply); // set up app_server emulation driver=new PreviewDriver(); if(!driver->Initialize()) printf("Uh-oh... Couldn't initialize graphics module for server emu!\n"); else { preview=driver->View(); AddChild(preview); preview->MoveTo(scrollview->Frame().right+20,scrollview->Frame().top); } ldata.highcolor.SetColor(51,102,160); pat_solid_high=0xFFFFFFFFFFFFFFFFLL; driver->FillRect(preview_bounds,&ldata,(int8*)&pat_solid_high); decorator=NULL; decorator_id=-1; GetDecorators(); LoadSettings(); } DecView::~DecView(void) { driver->Shutdown(); delete driver; if(decorator!=NULL) delete decorator; } void DecView::AllAttached(void) { declist->SetTarget(this); apply->SetTarget(this); declist->Select(0); } void DecView::MessageReceived(BMessage *msg) { switch(msg->what) { case APPLY_SETTINGS: { SaveSettings(); NotifyServer(); break; } case DECORATOR_CHOSEN: { #ifdef DEBUG_DECORATOR printf("MSG: Decorator Chosen - #%ld\n",declist->CurrentSelection()); #endif bool success=false; BString path( ConvertIndexToPath(declist->CurrentSelection()) ); #ifdef DEBUG_DECORATOR printf("MSG: Decorator path: %s\n",path.String()); #endif success=LoadDecorator(path.String()); if(!success) { #ifdef DEBUG_DECORATOR printf("MSG: Decorator NOT Chosen - couldn't load decorator\n"); #endif break; } ldata.highcolor.SetColor(colorset.desktop); driver->FillRect(preview_bounds,&ldata,(int8*)&pat_solid_high); if(decorator) { decorator->SetColors(colorset); decorator->Draw(); } break; } default: BView::MessageReceived(msg); break; } } void DecView::SaveSettings(void) { BString path(SETTINGS_DIR); path+="DecoratorSettings"; printf("%s\n",path.String()); BFile file(path.String(),B_READ_WRITE|B_CREATE_FILE|B_ERASE_FILE); settings.Flatten(&file); } void DecView::LoadSettings(void) { settings.MakeEmpty(); BDirectory dir,newdir; if(dir.SetTo(SETTINGS_DIR)==B_ENTRY_NOT_FOUND) create_directory(SETTINGS_DIR,0777); BString path(SETTINGS_DIR); path+="DecoratorSettings"; BFile file(path.String(),B_READ_ONLY); if(file.InitCheck()==B_OK) { if(settings.Unflatten(&file)==B_OK) { // Get the color for the current attribute here return; } printf("Error unflattening settings file %s\n",path.String()); } // If we get this far, we have encountered an error, so reset the settings // to the defaults SetDefaults(); } void DecView::SetDefaults(void) { settings.MakeEmpty(); // Add default settings here } void DecView::NotifyServer(void) { // Send a message to the app_server with the settings which we have. // While it might be worthwhile to someday have a separate protocol for // updating just one color, for now, we just need something to get things // done. Extract all the colors from the settings BMessage, attach them // to a PortLink message and fire it off to the server. // Name taken from ServerProtocol.h port_id serverport=find_port("OBappserver"); if(serverport==B_NAME_NOT_FOUND) return; PortLink *pl=new PortLink(serverport); // pl->SetOpCode(SET_UI_COLORS); // extract settings from settings object and attach to portlink object // pl->Flush(); delete pl; } void DecView::GetDecorators(void) { #ifdef DEBUG_DECORATOR printf("DecView::GetDecorators()\n"); #endif BDirectory dir; BEntry entry; BPath path; BString name; BStringItem *item; status_t dirstat=dir.SetTo(DECORATORS_DIR); if(dirstat!=B_OK) if(dirstat!=B_OK) { // We couldn't set the directory, so more than likely it just // doesn't exist. Create it and return an empty menu. switch(dirstat) { case B_NAME_TOO_LONG: { printf("DecView::GetDecorators: Couldn't open the folder for decorators - path string too long.\n"); break; } case B_ENTRY_NOT_FOUND: { printf("Couldn't open the folder for decorators - entry not found\n"); break; } case B_BAD_VALUE: { printf("DecView::GetDecorators: Couldn't open the folder for decorators - bad path\n"); break; } case B_NO_MEMORY: { printf("DecView::GetDecorators: No memory left. We're probably going to crash now\n"); break; } case B_BUSY: { printf("DecView::GetDecorators: Couldn't open the folder for decorators - node busy\n"); break; } case B_FILE_ERROR: { printf("DecView::GetDecorators: Couldn't open the folder for decorators - general file error\n"); break; } case B_NO_MORE_FDS: { printf("DecView::GetDecorators: Couldn't open the folder for decorators - no more file descriptors\n"); break; } } return; } int32 count=dir.CountEntries(); for(int32 i=0;iAddItem(item); } } bool DecView::LoadDecorator(const char *path) { if(!path) return false; create_decorator *pcreatefunc=NULL; get_decorator_version *pversionfunc=NULL; status_t stat; image_id addon; addon=load_add_on(path); stat=get_image_symbol(addon, "get_decorator_version", B_SYMBOL_TYPE_TEXT, (void**)&pversionfunc); if(stat!=B_OK) { unload_add_on(addon); #ifdef DEBUG_DECORATOR printf("LoadDecorator(%s): Couldn't get version symbol\n",path); #endif return false; } // As of now, we do nothing with decorator versions, but the possibility exists // that the API will change even though I cannot forsee any reason to do so. If // we *did* do anything with decorator versions, the assignment to a global would // go here. stat=get_image_symbol(addon, "instantiate_decorator", B_SYMBOL_TYPE_TEXT, (void**)&pcreatefunc); if(stat!=B_OK) { unload_add_on(addon); #ifdef DEBUG_DECORATOR printf("LoadDecorator(%s): Couldn't get allocation symbol\n",path); #endif return false; } if(decorator!=NULL) { #ifdef DEBUG_DECORATOR printf("LoadDecorator(): Deleting old decorator\n"); #endif delete decorator; decorator=NULL; // NEVER, *EVER*, call unload_add_on() if there is _any_ possibility, // no matter remote, that memory might still be in use when it is called. // It wll lead to unpredictable crashes which have almost nothing to // do with the *real* cause. // unload_add_on(decorator_id); } decorator_id=addon; decorator=pcreatefunc(BRect(50,50,150,150),WLOOK_TITLED,WFEEL_NORMAL,0); decorator->SetDriver(driver); decorator->SetFocus(true); // decorator->Draw(); return true; } BString DecView::ConvertIndexToPath(int32 index) { BStringItem *item=(BStringItem*)declist->ItemAt(index); if(!item) { #ifdef DEBUG_DECORATOR printf("ConvertIndexToPath(): Couldn't get item for index %ld\n",index); #endif return NULL; } BString path(DECORATORS_DIR); path+=item->Text(); #ifdef DEBUG_DECORATOR printf("ConvertIndexToPath(): returned %s\n",path.String()); #endif return BString(path.String()); } void DecView::SetColors(const BMessage &message) { #ifdef DEBUG_DECORATOR printf("DecView::SetColors\n"); #endif if(UnpackSettings(&colorset,&message)) { if(decorator) { ldata.highcolor.SetColor(colorset.desktop); driver->FillRect(preview_bounds,&ldata,(int8*)&pat_solid_high); decorator->SetColors(colorset); decorator->Draw(); } else { #ifdef DEBUG_DECORATOR printf("DecView::SetColors: NULL decorator\n"); #endif } } else { #ifdef DEBUG_DECORATOR printf("DecView::SetColors: UnpackSetting returned false\n"); #endif } } bool DecView::UnpackSettings(ColorSet *set, const BMessage *msg) { if(!set || !msg) { #ifdef DEBUG_DECORATOR printf("UnpackSettings(): NULL parameter\n"); #endif return false; } rgb_color *col; ssize_t size; // Once the OBOS app_server is in place, there will be more attributes if(msg->FindData("PANEL_BACKGROUND",(type_code)'RGBC',(const void**)&col,&size)==B_OK) set->panel_background.SetColor(*col); if(msg->FindData("MENU_BACKGROUND",(type_code)'RGBC',(const void**)&col,&size)==B_OK) set->menu_background.SetColor(*col); if(msg->FindData("MENU_SELECTION_BACKGROUND",(type_code)'RGBC',(const void**)&col,&size)==B_OK) set->menu_selected_background.SetColor(*col); if(msg->FindData("MENU_ITEM_TEXT",(type_code)'RGBC',(const void**)&col,&size)==B_OK) set->menu_text.SetColor(*col); if(msg->FindData("MENU_SELECTED_ITEM_TEXT",(type_code)'RGBC',(const void**)&col,&size)==B_OK) set->menu_selected_text.SetColor(*col); if(msg->FindData("WINDOW_TAB",(type_code)'RGBC',(const void**)&col,&size)==B_OK) set->window_tab.SetColor(*col); if(msg->FindData("KEYBOARD_NAVIGATION",(type_code)'RGBC',(const void**)&col,&size)==B_OK) set->keyboard_navigation.SetColor(*col); if(msg->FindData("DESKTOP",(type_code)'RGBC',(const void**)&col,&size)==B_OK) set->desktop.SetColor(*col); return true; }