From fe8567ec1c1bf4161bce89a837c8e31af0cfb51d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois=20Revol?= Date: Sun, 11 May 2008 00:40:56 +0000 Subject: [PATCH] The code for my (very useful if you ask me) AutoRaise deskbar addon that brings the focussed window to front after a timeout. MIT of course. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@25442 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/apps/autoraise/AutoRaise.rsrc | Bin 0 -> 6841 bytes src/apps/autoraise/AutoRaise.txt | 41 ++ src/apps/autoraise/AutoRaiseApp.cpp | 98 ++++ src/apps/autoraise/AutoRaiseApp.h | 26 ++ src/apps/autoraise/AutoRaiseIcon.cpp | 642 +++++++++++++++++++++++++++ src/apps/autoraise/AutoRaiseIcon.h | 94 ++++ src/apps/autoraise/common.h | 106 +++++ src/apps/autoraise/makefile | 121 +++++ src/apps/autoraise/settings.cpp | 85 ++++ src/apps/autoraise/settings.h | 68 +++ 10 files changed, 1281 insertions(+) create mode 100644 src/apps/autoraise/AutoRaise.rsrc create mode 100644 src/apps/autoraise/AutoRaise.txt create mode 100644 src/apps/autoraise/AutoRaiseApp.cpp create mode 100644 src/apps/autoraise/AutoRaiseApp.h create mode 100644 src/apps/autoraise/AutoRaiseIcon.cpp create mode 100644 src/apps/autoraise/AutoRaiseIcon.h create mode 100644 src/apps/autoraise/common.h create mode 100644 src/apps/autoraise/makefile create mode 100644 src/apps/autoraise/settings.cpp create mode 100644 src/apps/autoraise/settings.h diff --git a/src/apps/autoraise/AutoRaise.rsrc b/src/apps/autoraise/AutoRaise.rsrc new file mode 100644 index 0000000000000000000000000000000000000000..347334e84f34a16d96d832cf8090bb5e7b2fc098 GIT binary patch literal 6841 zcmeHMOK;Oa5T5dA0hPKm65w0zh$61JSZNYlmXbP(t16t5DB%$aCsiM`CvwYyvws9g z9Qa%O1SF&|v$N~0A88xfsuFl2+dKQs%+Aivc&%*92Y^kl`UoFYx>oV_7eu;%xTj`e*F;2sYHKd}Av4l`|PK6YV9O`R<5q8Y^!8Ap%RNay z=p7IH#na(vFg`6FlCkA%-WF z_CpIFDU3QG1Zz5lFbF4E0t9z~1SX5{ZWp>2;V7W=4MoBow2%5^Ai{q$u{VfMyC|XI zznFv>bRPwf=KdMxoPcneKRzP+rlrWlF$fZbxM84AMjVeMCa?e}337wsv_8)hV1ukH z`zi?BCjfcl@r?oz6w+&=Z$AFIH@siAD`EDmVbI}X5lo?y#Cc{=g;eoK(hXm^`6|{ll!^YU&Y5C@823P zObb3L0TZsy$M@5${WDoFNnWqHeEu>5GO;eR{&G3RyO!2dy`Ra1&XZ-Gr}x{{`6!v_ zYhPbV!IKZk^-l7-Qt#m4? z9X!xwz)sEcOXX&>W7o@$A8kMTQix7Bp3H^zYc1dPb|bM}uj0}lICSu`$zt`AzgO+J z6_k31y>uk92IW@Cvu${f%zeC8MTcgl;x@<(oeN1bjkp;+X^ES8kYUDexDA@sL%bf( jo%UTPa@cWvAws7$awOZW*E)M|nzi}tzYY4IQ2_n`zLp*x literal 0 HcmV?d00001 diff --git a/src/apps/autoraise/AutoRaise.txt b/src/apps/autoraise/AutoRaise.txt new file mode 100644 index 0000000000..5891f4bcf6 --- /dev/null +++ b/src/apps/autoraise/AutoRaise.txt @@ -0,0 +1,41 @@ +AutoRaise : beyond FocusFollowsMouse, for BeOS +(c) 2002, mmu_man, revol@free.fr +Released under MIT licence, +usual disclaimer applies, blah blah blah... + + +This tiny Deskbar replicant is a window autoraiser. It will bring to front whatever window is under the mouse after a selectable delay. + + +Installation: +- put the AutoRaise folder where you want (I suggest /boot/apps), +- you can delete the src/ folder if you aren't interested in the sources, +- double-click on either the 'Put me in Deskbar', or 'Put me in Deskbar (persistant)', the later will keep it in between boots. + + +Alternately, you can run it in a Terminal: +AutoRaise --deskbar + +or, if you want it to be reloaded on each boot: +AutoRaise --deskbar --persist + + +Customisation: +* Left-click will toggles activation. + +* right-click brings a menu: + * Active: check it to activate auto raising + * Mode: The default mode (option 1) is to raise every window. You can also set it so it only raises the Deskbar, whenever you have the mouse on top of it, even if you have a window over it (option 2), or rather only when your mouse is over a visible part of it (option 3). + * Inactive behaviour: This sets up the mouse behaviour when AutoRaise is NOT active. This takes effects only when it's not active (either immediately or when you disables it). It's the same control as the "Focus follows mouse" in the Mouse preferences panel, however I recommend you don't run the preference panel while AutoRaise is active, as it will conflict, and you will get funky behaviour :)) + * Delay: allows you to change the delay before the focused window is brought to front. + +Informations: +There is a special version for Dano, since it provides some helpful API... +To get it just recompile it, it will detect itself it is compiled under R5.1. +I'm not sure the Dano version still compiles however, as I begun this proggy under Dano, but finished it in R5, and didn't check back, since I don't use it much. + +The R5 version has a problem on tabs, because there isn't any mean to know the window tab position and size. So it acts as if the tab was as wide as the window, (it uses the outer region). + + +The code was based on parts of Deskscope, 2000 Shamyl Zakariya +Sorry it's really ugly, but it does the job :) diff --git a/src/apps/autoraise/AutoRaiseApp.cpp b/src/apps/autoraise/AutoRaiseApp.cpp new file mode 100644 index 0000000000..c348a228a7 --- /dev/null +++ b/src/apps/autoraise/AutoRaiseApp.cpp @@ -0,0 +1,98 @@ +#include "AutoRaiseApp.h" +#include "AutoRaiseIcon.h" + +AutoRaiseApp::AutoRaiseApp() + : BApplication( APP_SIG ) +{ + removeFromDeskbar(NULL); + _directToDeskbar = false; + + //since the tray item shows an icon, and the class TrayView needs to be able to know the location + //of the executing binary, we write into the settings file this critical information when the app is fired up + app_info info; + be_app->GetAppInfo(&info); + + //now, put the path into the settings file + AutoRaiseSettings settings; + settings.SetAppPath(info.ref); +} + +AutoRaiseApp::~AutoRaiseApp() +{ + return; +} + +void AutoRaiseApp::ArgvReceived(int32 argc, char ** argv) +{ + BString option; + bool inDeskbar = false, persist = false; + + for (int32 i = 1; i < argc; i++) + { + option = argv[i]; + if (option.IFindFirst("deskbar") != B_ERROR) + inDeskbar = true; + + if (option.IFindFirst("persist") != B_ERROR) + persist = true; + } + + if (inDeskbar && !persist) + { + printf(APP_NAME" being put into Tray (one shot)...\n"); + + PutInTray(false); + + _directToDeskbar = true; + + } + else if (inDeskbar && persist) + { + printf(APP_NAME" being put into Tray (persistant)...\n"); + + PutInTray(true); + + _directToDeskbar = true; + } + else + { + printf("\nUsage: "APP_NAME" [options]\n\t--deskbar\twill not open window, will just put "APP_NAME" into tray\n\t--persist will put "APP_NAME" into tray such that it remains between bootings\n"); + } + + be_app_messenger.SendMessage(B_QUIT_REQUESTED); +} + +void AutoRaiseApp::ReadyToRun() +{ + if (!_directToDeskbar) + { + printf("\nUsage: " APP_NAME " [options]\n\t--deskbar\twill not open window, will just put " APP_NAME " into tray\n\t--persist will put " APP_NAME " into tray such that it remains between bootings\n"); + BAlert *alert = new BAlert("usage box", APP_NAME ", (c) 2002, mmu_man\nUsage: " APP_NAME " [options]\n\t--deskbar\twill not open window, will just put " APP_NAME " into tray\n\t--persist will put "APP_NAME" into tray such that it remains between bootings\n", "Ok", NULL, NULL, + B_WIDTH_AS_USUAL, B_OFFSET_SPACING, B_INFO_ALERT); + alert->SetShortcut(0, B_ENTER); + alert->Go(); + be_app_messenger.SendMessage(B_QUIT_REQUESTED); + } +} + +void AutoRaiseApp::PutInTray(bool persist) +{ + BDeskbar db; + + if (!persist) + db.AddItem(new TrayView); + else { + BRoster roster; + entry_ref ref; + roster.FindApp(APP_SIG, &ref); + int32 id; + db.AddItem(&ref, &id); + } +} + +int main() +{ + AutoRaiseApp *app = new AutoRaiseApp(); + app->Run(); + +} diff --git a/src/apps/autoraise/AutoRaiseApp.h b/src/apps/autoraise/AutoRaiseApp.h new file mode 100644 index 0000000000..f36ec71feb --- /dev/null +++ b/src/apps/autoraise/AutoRaiseApp.h @@ -0,0 +1,26 @@ +#ifndef ICON_H +#define ICON_H + +#include +#include +#include + +#include "common.h" +#include "settings.h" + + +class AutoRaiseApp: public BApplication{ + protected: + bool _directToDeskbar; + + public: + AutoRaiseApp(); + virtual ~AutoRaiseApp(); + virtual bool QuitRequested() { return true; } + virtual void ArgvReceived(int32 argc, char ** args); + virtual void ReadyToRun(); + + void PutInTray(bool); +}; + +#endif diff --git a/src/apps/autoraise/AutoRaiseIcon.cpp b/src/apps/autoraise/AutoRaiseIcon.cpp new file mode 100644 index 0000000000..ca30e3ac3e --- /dev/null +++ b/src/apps/autoraise/AutoRaiseIcon.cpp @@ -0,0 +1,642 @@ +/* this is for the DANO hack (new, simpler version than the BStringIO hack) */ +#include +#ifdef B_BEOS_VERSION_DANO +#define private public +#include +#undef private +#endif + +#include "AutoRaiseIcon.h" +#include +#include +#include +#include +#include + + +extern "C" _EXPORT BView *instantiate_deskbar_item(void) +{ + puts("Instanciating AutoRaise TrayView..."); + return (new TrayView); +} + + +long removeFromDeskbar(void *) +{ + BDeskbar db; + if (db.RemoveItem(APP_NAME) != B_OK) + printf("Unable to remove AutoRaise from BDeskbar\n"); + + return 0; +} + +//************************************************** + +ConfigMenu::ConfigMenu(TrayView *tv, bool useMag) + :BPopUpMenu("config_popup", false, false){ + + BMenu *tmpm; + BMenuItem *tmpi; + BMessage *msg; + bigtime_t delay; + + AutoRaiseSettings *s = tv->Settings(); + + SetFont(be_plain_font); + + + BMenuItem *active = new BMenuItem("Active", new BMessage(MSG_TOOGLE_ACTIVE)); + active->SetMarked(s->Active()); + AddItem(active); + + tmpm = new BMenu("Mode"); + tmpm->SetFont(be_plain_font); + + msg = new BMessage(MSG_SET_MODE); + msg->AddInt32(AR_MODE, Mode_All); + tmpi = new BMenuItem("Default (all windows)", msg); + tmpi->SetMarked(s->Mode() == Mode_All); + tmpm->AddItem(tmpi); + + msg = new BMessage(MSG_SET_MODE); + msg->AddInt32(AR_MODE, Mode_DeskbarOver); + tmpi = new BMenuItem("Deskbar only (over its area)", msg); + tmpi->SetMarked(s->Mode() == Mode_DeskbarOver); +#ifdef USE_DANO_HACK + tmpi->SetEnabled(false); +#endif + tmpm->AddItem(tmpi); + + msg = new BMessage(MSG_SET_MODE); + msg->AddInt32(AR_MODE, Mode_DeskbarTouch); + tmpi = new BMenuItem("Deskbar only (touch)", msg); + tmpi->SetMarked(s->Mode() == Mode_DeskbarTouch); + tmpm->AddItem(tmpi); + + + tmpm->SetTargetForItems(tv); + BMenuItem *modem = new BMenuItem(tmpm); + modem->SetEnabled(s->Active()); + AddItem(modem); + + tmpm = new BMenu("Inactive behaviour"); + tmpm->SetFont(be_plain_font); + + msg = new BMessage(MSG_SET_BEHAVIOUR); + msg->AddInt32(AR_BEHAVIOUR, B_NORMAL_MOUSE); + tmpi = new BMenuItem("Normal", msg); + tmpi->SetMarked(tv->fNormalMM == B_NORMAL_MOUSE); + tmpm->AddItem(tmpi); + + msg = new BMessage(MSG_SET_BEHAVIOUR); + msg->AddInt32(AR_BEHAVIOUR, B_FOCUS_FOLLOWS_MOUSE); + tmpi = new BMenuItem("Focus follows mouse", msg); + tmpi->SetMarked(tv->fNormalMM == B_FOCUS_FOLLOWS_MOUSE); + tmpm->AddItem(tmpi); + + msg = new BMessage(MSG_SET_BEHAVIOUR); + msg->AddInt32(AR_BEHAVIOUR, B_WARP_MOUSE); + tmpi = new BMenuItem("Warping (ffm)", msg); + tmpi->SetMarked(tv->fNormalMM == B_WARP_MOUSE); + tmpm->AddItem(tmpi); + + msg = new BMessage(MSG_SET_BEHAVIOUR); + msg->AddInt32(AR_BEHAVIOUR, B_INSTANT_WARP_MOUSE); + tmpi = new BMenuItem("Instant warping (ffm)", msg); + tmpi->SetMarked(tv->fNormalMM == B_INSTANT_WARP_MOUSE); + tmpm->AddItem(tmpi); + + tmpm->SetTargetForItems(tv); + BMenuItem *behavm = new BMenuItem(tmpm); + AddItem(behavm); + + + tmpm = new BMenu("Delay"); + tmpm->SetFont(be_plain_font); + + msg = new BMessage(MSG_SET_DELAY); + msg->AddInt64(AR_DELAY, 100000LL); + tmpi = new BMenuItem("0.1 s", msg); + tmpi->SetMarked(tv->raise_delay == 100000LL); + tmpm->AddItem(tmpi); + + msg = new BMessage(MSG_SET_DELAY); + msg->AddInt64(AR_DELAY, 200000LL); + tmpi = new BMenuItem("0.2 s", msg); + tmpi->SetMarked(tv->raise_delay == 200000LL); + tmpm->AddItem(tmpi); + + msg = new BMessage(MSG_SET_DELAY); + msg->AddInt64(AR_DELAY, 500000LL); + tmpi = new BMenuItem("0.5 s", msg); + tmpi->SetMarked(tv->raise_delay == 500000LL); + tmpm->AddItem(tmpi); + + msg = new BMessage(MSG_SET_DELAY); + msg->AddInt64(AR_DELAY, 1000000LL); + tmpi = new BMenuItem("1 s", msg); + tmpi->SetMarked(tv->raise_delay == 1000000LL); + tmpm->AddItem(tmpi); + + msg = new BMessage(MSG_SET_DELAY); + msg->AddInt64(AR_DELAY, 2000000LL); + tmpi = new BMenuItem("2 s", msg); + tmpi->SetMarked(tv->raise_delay == 2000000LL); + tmpm->AddItem(tmpi); + + msg = new BMessage(MSG_SET_DELAY); + msg->AddInt64(AR_DELAY, 3000000LL); + tmpi = new BMenuItem("3 s", msg); + tmpi->SetMarked(tv->raise_delay == 3000000LL); + tmpm->AddItem(tmpi); + + msg = new BMessage(MSG_SET_DELAY); + msg->AddInt64(AR_DELAY, 4000000LL); + tmpi = new BMenuItem("4 s", msg); + tmpi->SetMarked(tv->raise_delay == 4000000LL); + tmpm->AddItem(tmpi); + + msg = new BMessage(MSG_SET_DELAY); + msg->AddInt64(AR_DELAY, 5000000LL); + tmpi = new BMenuItem("5 s", msg); + tmpi->SetMarked(tv->raise_delay == 5000000LL); + tmpm->AddItem(tmpi); + + tmpm->SetTargetForItems(tv); + BMenuItem *delaym = new BMenuItem(tmpm); + delaym->SetEnabled(s->Active()); + + AddItem(delaym); + + AddSeparatorItem(); +// AddItem(new BMenuItem("Settings...", new BMessage(OPEN_SETTINGS))); + + AddItem(new BMenuItem("About "APP_NAME, new BMessage(B_ABOUT_REQUESTED))); + AddItem(new BMenuItem("Remove from tray", new BMessage(REMOVE_FROM_TRAY))); + + SetTargetForItems(tv); + SetAsyncAutoDestruct(true); +} + +ConfigMenu::~ConfigMenu() {} + +//************************************************ + +TrayView::TrayView() + :BView(BRect(0, 0, B_MINI_ICON, B_MINI_ICON -1), "AutoRaise", B_FOLLOW_LEFT | B_FOLLOW_TOP, B_WILL_DRAW){ + _init(); //Initialization common to both constructors +} + +//Rehydratable constructor +TrayView::TrayView(BMessage *mdArchive):BView(mdArchive){ + _init(); //As above +} + +void TrayView::GetPreferredSize(float *w, float *h) +{ + *w = B_MINI_ICON; + *h = B_MINI_ICON - 1; +} + +void TrayView::_init() +{ + thread_info ti; + status_t err; + + watching = false; + _settings = new AutoRaiseSettings; + + _appPath = _settings->AppPath(); + + raise_delay = _settings->Delay(); + current_window = 0; + polling_delay = 100000; + fPollerSem = create_sem(0, "AutoRaise poller sync"); + last_raiser_thread = 0; + fNormalMM = mouse_mode(); + + _activeIcon = NULL; + _inactiveIcon = NULL; + + get_thread_info(find_thread(NULL), &ti); + fDeskbarTeam = ti.team; + +#ifndef USE_DANO_HACK + resume_thread(poller_thread = spawn_thread(poller, "AutoRaise desktop poller", B_NORMAL_PRIORITY, (void *)this)); +#endif + + //determine paths to icon files based on app path in settings file + + BResources res; + BFile theapp(&_appPath, B_READ_ONLY); + if ((err = res.SetTo(&theapp)) != B_OK) { + + printf("Unable to find the app to get the resources !!!\n"); +// removeFromDeskbar(NULL); +// delete _settings; +// return; + } + + size_t bmsz; + char *p; + + p = (char *)res.LoadResource('MICN', ACTIVE_ICON, &bmsz); + _activeIcon = new BBitmap(BRect(0, 0, B_MINI_ICON-1, B_MINI_ICON -1), B_CMAP8); + if (!p) + puts("ERROR loading active icon"); + else + _activeIcon->SetBits(p, B_MINI_ICON*B_MINI_ICON, 0, B_CMAP8); + + p = (char *)res.LoadResource('MICN', INACTIVE_ICON, &bmsz); + _inactiveIcon = new BBitmap(BRect(0, 0, B_MINI_ICON-1, B_MINI_ICON -1), B_CMAP8); + if (!p) + puts("ERROR loading inactive icon"); + else + _inactiveIcon->SetBits(p, B_MINI_ICON*B_MINI_ICON, 0, B_CMAP8); + + + SetDrawingMode(B_OP_ALPHA); + SetFlags(Flags() | B_WILL_DRAW); + + // begin watching if we want + // (doesn't work here, better do it in AttachedToWindow()) +} + +TrayView::~TrayView(){ + status_t ret; + + if (watching) { +#ifdef USE_DANO_HACK + be_roster->StopWatching(this); +#else +// acquire_sem(fPollerSem); +#endif + set_mouse_mode(fNormalMM); + watching = false; + } + delete_sem(fPollerSem); +#ifndef USE_DANO_HACK + wait_for_thread(poller_thread, &ret); +#endif + if (_activeIcon) delete _activeIcon; + if (_inactiveIcon) delete _inactiveIcon; + if (_settings) delete _settings; + + return; +} + +//Dehydrate into a message (called by the DeskBar) +status_t TrayView::Archive(BMessage *data, bool deep = true) const { +// BEntry appentry(&_appPath, true); +// BPath appPath(&appentry); + status_t error=BView::Archive(data, deep); + data->AddString("add_on", APP_SIG); +// data->AddFlat("_appPath", (BFlattenable *) &_appPath); + data->AddRef("_appPath", &_appPath); + + return B_NO_ERROR; +} + +//Rehydrate the View from a given message (called by the DeskBar) +TrayView *TrayView::Instantiate(BMessage *data) { + + if (!validate_instantiation(data, "TrayView")) + { + return NULL; + } + + return (new TrayView(data)); +} + +void TrayView::AttachedToWindow() { + if(Parent()) + SetViewColor(Parent()->ViewColor()); + if (_settings->Active()) { + fNormalMM = mouse_mode(); + set_mouse_mode(B_FOCUS_FOLLOWS_MOUSE); +#ifdef USE_DANO_HACK + be_roster->StartWatching(this, B_REQUEST_WINDOW_ACTIVATED); +#else + release_sem(fPollerSem); +#endif + watching = true; + } +} + +void TrayView::Draw(BRect updaterect) { + BRect bnds(Bounds()); + + if (Parent()) SetHighColor(Parent()->ViewColor()); + else SetHighColor(189, 186, 189, 255); + FillRect(bnds); + + if (_settings->Active()) + { + if (_activeIcon) DrawBitmap(_activeIcon); + } + else + { + if (_inactiveIcon) DrawBitmap(_inactiveIcon); + } +} + +void TrayView::MouseDown(BPoint where) { + BWindow *window = Window(); /*To handle the MouseDown message*/ + if (!window) /*Check for proper instantiation*/ + return; + + BMessage *mouseMsg = window->CurrentMessage(); + if (!mouseMsg) /*Check for existence*/ + return; + + if (mouseMsg->what == B_MOUSE_DOWN) { + /*Variables for storing the button pressed / modifying key*/ + uint32 buttons = 0; + uint32 modifiers = 0; + + /*Get the button pressed*/ + mouseMsg->FindInt32("buttons", (int32 *) &buttons); + /*Get modifier key (if any)*/ + mouseMsg->FindInt32("modifiers", (int32 *) &modifiers); + + /*Now perform action*/ + switch(buttons) { + case B_PRIMARY_MOUSE_BUTTON: + { + SetActive(!_settings->Active()); + + break; + } + case B_SECONDARY_MOUSE_BUTTON: + { + ConvertToScreen(&where); + + //menu will delete itself (see constructor of ConfigMenu), + //so all we're concerned about is calling Go() asynchronously + ConfigMenu *menu = new ConfigMenu(this, false); + menu->Go(where, true, true, ConvertToScreen(Bounds()), true); + + break; + } + } + } +} + + +int32 fronter(void *arg) +{ + TrayView *tv = (TrayView *)arg; + int32 tok = tv->current_window; + int32 ws = current_workspace(); + sem_id sem = tv->fPollerSem; + int32 *tl, tlc; + window_info *wi; + + snooze(tv->raise_delay); + +#ifndef USE_DANO_HACK + if (acquire_sem(sem) != B_OK) + return B_OK; // this really needs a better locking model... +#endif + if (ws != current_workspace()) + goto end; // don't touch windows if we changed workspace + if (tv->last_raiser_thread != find_thread(NULL)) + goto end; // seems a newer one has been spawn, exit +PRINT(("tok = %ld cw = %ld\n", tok, tv->current_window)); + if (tok == tv->current_window) { + bool doZoom = false; + BRect zoomRect(0.0f, 0.0f, 10.0f, 10.0f); + do_window_action(tok, B_BRING_TO_FRONT, zoomRect, doZoom); + } + + end: + release_sem(sem); + return B_OK; +} + +#ifndef USE_DANO_HACK + +int32 poller(void *arg) +{ + TrayView *tv = (TrayView *)arg; + volatile int32 tok = tv->current_window; + int32 *tl = NULL; + int32 i, tlc; + window_info *wi = NULL; + + int pass=0; + BPoint mouse; + uint32 buttons; + + while (acquire_sem(tv->fPollerSem) == B_OK) { + release_sem(tv->fPollerSem); + pass++; + BLooper *l = tv->Looper(); + if (!l || l->LockWithTimeout(500000) != B_OK) + continue; + tv->GetMouse(&mouse, &buttons); + tv->ConvertToScreen(&mouse); + tv->Looper()->Unlock(); + if (buttons) // we don't want to interfere when the user is moving a window or something... + goto zzz; + + tl = get_token_list(-1, &tlc); + for (i=0; ilayer < 3) // we hit the desktop or a window not on this WS + goto zzz; + if ((wi->window_left > wi->window_right) || (wi->window_top > wi->window_bottom)) + goto zzz; // invalid window ? +/* +printf("if (!%s && (%li, %li)isin(%li)(%li, %li, %li, %li) && (%li != %li) ", wi->is_mini?"true":"false", + (long)mouse.x, (long)mouse.y, i, wi->window_left, wi->window_right, wi->window_top, wi->window_bottom, wi->id, tok); +*/ + + + if ((!wi->is_mini) + && (((long)mouse.x) > wi->window_left) && (((long)mouse.x) < wi->window_right) + && (((long)mouse.y) > wi->window_top) && (((long)mouse.y) < wi->window_bottom)) { +//((tv->_settings->Mode() != Mode_DeskbarOver) || (wi->team == tv->fDeskbarTeam)) + + if ((tv->_settings->Mode() == Mode_All) && (wi->id == tv->current_window)) + goto zzz; // already raised + + if ((tv->_settings->Mode() == Mode_All) || (wi->team == tv->fDeskbarTeam)) { + tv->current_window = wi->id; + tok = wi->id; + resume_thread(tv->last_raiser_thread = spawn_thread(fronter, "fronter", B_NORMAL_PRIORITY, (void *)tv)); + goto zzz; + } else if (tv->_settings->Mode() == Mode_DeskbarTouch) // give up, before we find Deskbar under it + goto zzz; + } + free(wi); + wi=NULL; + } else + goto zzz; + } + zzz: +// puts(""); + if (wi) free(wi); + wi = NULL; + if (tl) free(tl); + tl = NULL; + snooze(tv->polling_delay); + } + return B_OK; +} + +#endif + +void TrayView::MessageReceived(BMessage* message) +{ + BMessenger msgr; + int32 *tl, tlc; + port_id pi; + int32 tok; + window_info *wi; + + BAlert *alert; + bigtime_t delay; + int32 mode; + bool wasactive; + BPoint mouse; + uint32 buttons; + + switch(message->what) + { + case MSG_TOOGLE_ACTIVE: + SetActive(!_settings->Active()); + break; + case MSG_SET_ACTIVE: + SetActive(true); + break; + case MSG_SET_INACTIVE: + SetActive(false); + break; + case MSG_SET_DELAY: + delay = DEFAULT_DELAY; + message->FindInt64(AR_DELAY, &delay); + raise_delay = delay; + _settings->SetDelay(delay); + break; + case MSG_SET_MODE: + mode = Mode_All; + message->FindInt32(AR_MODE, &mode); + _settings->SetMode(mode); + break; + case MSG_SET_BEHAVIOUR: + message->FindInt32(AR_BEHAVIOUR, &mode); + wasactive = _settings->Active(); + if (wasactive) + SetActive(false); + fNormalMM = (mode_mouse)mode; + set_mouse_mode(fNormalMM); + if (wasactive) + SetActive(true); + break; + case REMOVE_FROM_TRAY: + { + thread_id tid = spawn_thread(removeFromDeskbar, "RemoveFromDeskbar", B_NORMAL_PRIORITY, NULL); + if (tid) resume_thread(tid); + + break; + } + case B_ABOUT_REQUESTED: + alert = new BAlert("about box", "AutoRaise, (c) 2002, mmu_man\nEnjoy :-)", "Ok", NULL, NULL, + B_WIDTH_AS_USUAL, B_OFFSET_SPACING, B_INFO_ALERT); + alert->SetShortcut(0, B_ENTER); + alert->Go(NULL); // use asynchronous version + break; + case OPEN_SETTINGS: + + break; +#ifdef USE_DANO_HACK + case B_SOME_WINDOW_ACTIVATED: +// printf("Window Activated\n"); +// message->PrintToStream(); + GetMouse(&mouse, &buttons); + if (buttons) + break; + if (message->FindMessenger("be:window", &msgr) < B_OK) + puts("BMsgr ERROR"); + else { + bool doZoom = false; + BRect zoomRect(0.0f, 0.0f, 0.0f, 0.0f); + pi = msgr.fPort; +// printf("port:%li (%lx)\n", pi, pi); + + tl = get_token_list(msgr.Team(), &tlc); +// printf("tokens (team %li): (%li) ", msgr.Team(), tlc); + for (tlc; tlc; tlc--) { +// printf("%li ", tl[tlc-1]); + wi = get_window_info(tl[tlc-1]); + if (wi) { + if (wi->client_port == pi) { + if ((wi->layer < 3) // we hit the desktop or a window not on this WS + || (wi->window_left > wi->window_right) || (wi->window_top > wi->window_bottom) + || (wi->is_mini) + || (/*(_settings->Mode() == Mode_All) && */(wi->id == current_window))) { + // already raised + free(wi); + break; + } + + if ((_settings->Mode() == Mode_All) || (wi->team == fDeskbarTeam)) { + PRINT(("raising wi=%li, cp=%ld, pi=%ld team=%ld DBteam=%ld\n", wi->id, wi->client_port, pi, wi->team, fDeskbarTeam)); + current_window = wi->id; + tok = wi->id; + resume_thread(last_raiser_thread = spawn_thread(fronter, "fronter", B_NORMAL_PRIORITY, (void *)this)); + } else { + current_window = wi->id; + } + } + free(wi); + } + } +// puts(""); + free(tl); + } + break; +#endif + default: + BView::MessageReceived(message); + } +} + +AutoRaiseSettings *TrayView::Settings() const +{ + return _settings; +} + +void TrayView::SetActive(bool st) +{ + _settings->SetActive(st); + if (_settings->Active()) + { + if (!watching) { + fNormalMM = mouse_mode(); + set_mouse_mode(B_FOCUS_FOLLOWS_MOUSE); +#ifdef USE_DANO_HACK + be_roster->StartWatching(this, B_REQUEST_WINDOW_ACTIVATED); +#else + release_sem(fPollerSem); +#endif + watching = true; + } + } + else + { + if (watching) { +#ifdef USE_DANO_HACK + be_roster->StopWatching(this); +#else + acquire_sem(fPollerSem); +#endif + set_mouse_mode(fNormalMM); + watching = false; + } + } + Invalidate(); +} + diff --git a/src/apps/autoraise/AutoRaiseIcon.h b/src/apps/autoraise/AutoRaiseIcon.h new file mode 100644 index 0000000000..3d6d3eaefd --- /dev/null +++ b/src/apps/autoraise/AutoRaiseIcon.h @@ -0,0 +1,94 @@ +#ifndef TRAY_VIEW +#define TRAY_VIEW + +#include +#include +#include +#include + + +#include "common.h" +#include "settings.h" +#include + +//exported instantiator function +extern "C" _EXPORT BView* instantiate_deskbar_item(); + + +//since we can't remove the view from the deskbar from within the same thread +//as tray view, a thread will be spawned and this function called. It removed TrayView +//from the Deskbar +long removeFromDeskbar(void *); + +class _EXPORT TrayView; + + +/********************************************* + class TrayView derived from BView + + The icon in the Deskbar tray, provides the fundamental + user interface. Archivable, so it can be flattened and fired + at the deskbar. + +*********************************************/ + +class TrayView:public BView{ + private: + + BBitmap *_activeIcon, *_inactiveIcon; + entry_ref _appPath; + bool watching; + + void _init(void); //initialization common to all constructors + + public: + AutoRaiseSettings *_settings; + mode_mouse fNormalMM; + volatile int32 current_window; // id + bigtime_t raise_delay; + volatile thread_id last_raiser_thread; + team_id fDeskbarTeam; + + bigtime_t polling_delay; // for !DANO + sem_id fPollerSem; + thread_id poller_thread; + + TrayView(); + TrayView(BMessage *mdArchive); + virtual ~TrayView(); + + virtual status_t Archive(BMessage *data, bool deep = true) const; + static TrayView *Instantiate(BMessage *data); + + virtual void Draw(BRect updateRect ); + virtual void AttachedToWindow(); + virtual void MouseDown(BPoint where); + virtual void MessageReceived(BMessage* message); + virtual void GetPreferredSize(float *w, float *h); + + AutoRaiseSettings *Settings() const; + void SetActive(bool); +}; + +int32 fronter(void *); +int32 poller(void *); + +/********************************************* + ConfigMenu derived from BPopUpMenu + Provides the contextual left-click menu for the + TrayView. Fires it's messages at the TrayView specified + in it's constructor; + Also, it's by default set to asynchronously destruct, + so it's basically a fire & forget kinda fella. +*********************************************/ + +class ConfigMenu: public BPopUpMenu{ + private: + + public: + ConfigMenu(TrayView *tv, bool useMag); + virtual ~ConfigMenu(); +}; + + +#endif diff --git a/src/apps/autoraise/common.h b/src/apps/autoraise/common.h new file mode 100644 index 0000000000..b7d62f280f --- /dev/null +++ b/src/apps/autoraise/common.h @@ -0,0 +1,106 @@ +#ifndef COMMON_H +#define COMMON_H + +#include + +#include +#include +#include +#include + + +// R5.1 has a very helpful API... +#if (B_BEOS_VERSION == 0x0510) +#define USE_DANO_HACK +#endif + +/*************************************************** + common.h + Constants used by app +***************************************************/ + +// used to check the image to use to get the resources +#define APP_NAME "AutoRaise" +#define APP_SIG "application/x-vnd.mmu.AutoRaise" +#define SETTINGS_FILE "x-vnd.mmu.AutoRaise_settings" + +//names of data segments in settings file +//also used in messages + +#define DEFAULT_DELAY 500000LL + +// float: delay before raise +#define AR_DELAY "ar:delay" +// bool: last state +#define AR_ACTIVE "ar:active" + +#define AR_MODE "ar:mode" +enum { + Mode_All, + Mode_DeskbarOver, + Mode_DeskbarTouch +}; + +#define AR_BEHAVIOUR "ar:behaviour" + +// resources +#define ACTIVE_ICON "AR:ON" +#define INACTIVE_ICON "AR:OFF" + +// messages + +#define ADD_TO_TRAY 'zATT' +#define REMOVE_FROM_TRAY 'zRFT' + +#define OPEN_SETTINGS 'zOPS' + + +#define MSG_DELAY_POPUP 'arDP' + +#define MSG_TOOGLE_ACTIVE 'arTA' +#define MSG_SET_ACTIVE 'arSA' +#define MSG_SET_INACTIVE 'arSI' +#define MSG_SET_DELAY 'arSD' +#define MSG_SET_MODE 'arSM' +#define MSG_SET_BEHAVIOUR 'arSB' + +/* from OpenTracker deskbar/WindowMenuItem.h */ + +// from interface_defs.h +struct window_info { + team_id team; + int32 id; /* window's token */ + + int32 thread; + int32 client_token; + int32 client_port; + uint32 workspaces; + + int32 layer; + uint32 w_type; /* B_TITLED_WINDOW, etc. */ + uint32 flags; /* B_WILL_FLOAT, etc. */ + int32 window_left; + int32 window_top; + int32 window_right; + int32 window_bottom; + int32 show_hide_level; + bool is_mini; + char name[1]; +}; + +// from interface_misc.h +enum window_action { + B_MINIMIZE_WINDOW, + B_BRING_TO_FRONT +}; + +// from interface_misc.h +void do_window_action(int32 window_id, int32 action, + BRect zoomRect, bool zoom); +window_info *get_window_info(int32 a_token); +int32 *get_token_list(team_id app, int32 *count); +void do_minimize_team(BRect zoomRect, team_id team, bool zoom); +void do_bring_to_front_team(BRect zoomRect, team_id app, bool zoom); + + +#endif diff --git a/src/apps/autoraise/makefile b/src/apps/autoraise/makefile new file mode 100644 index 0000000000..2d9d771a4d --- /dev/null +++ b/src/apps/autoraise/makefile @@ -0,0 +1,121 @@ +## BeOS Generic Makefile v2.2 ## + +## Fill in this file to specify the project being created, and the referenced +## makefile-engine will do all of the hard work for you. This handles both +## Intel and PowerPC builds of the BeOS. + +## Application Specific Settings --------------------------------------------- + +# specify the name of the binary +NAME= AutoRaise + +# specify the type of binary +# APP: Application +# SHARED: Shared library or add-on +# STATIC: Static library archive +# DRIVER: Kernel Driver +TYPE= APP + +# add support for new Pe and Eddie features +# to fill in generic makefile + +#%{ +# @src->@ + +# specify the source files to use +# full paths or paths relative to the makefile can be included +# all files, regardless of directory, will have their object +# files created in the common object directory. +# Note that this means this makefile will not work correctly +# if two source files with the same name (source.c or source.cpp) +# are included from different directories. Also note that spaces +# in folder names do not work well with this makefile. +#SRCS= AutoRaiseApp.cpp AutoRaiseWindow.cpp AutoRaiseIcon.cpp +SRCS= AutoRaiseApp.cpp AutoRaiseIcon.cpp settings.cpp + +# specify the resource files to use +# full path or a relative path to the resource file can be used. +RSRCS= AutoRaise.rsrc + +# @<-src@ +#%} + +# end support for Pe and Eddie + +# specify additional libraries to link against +# there are two acceptable forms of library specifications +# - if your library follows the naming pattern of: +# libXXX.so or libXXX.a you can simply specify XXX +# library: libbe.so entry: be +# +# - if your library does not follow the standard library +# naming scheme you need to specify the path to the library +# and it's name +# library: my_lib.a entry: my_lib.a or path/my_lib.a +LIBS= be stdc++.r4 zeta + +# specify additional paths to directories following the standard +# libXXX.so or libXXX.a naming scheme. You can specify full paths +# or paths relative to the makefile. The paths included may not +# be recursive, so include all of the paths where libraries can +# be found. Directories where source files are found are +# automatically included. +LIBPATHS= + +# additional paths to look for system headers +# thes use the form: #include
+# source file directories are NOT auto-included here +SYSTEM_INCLUDE_PATHS = + +# additional paths to look for local headers +# thes use the form: #include "header" +# source file directories are automatically included +LOCAL_INCLUDE_PATHS = + +# specify the level of optimization that you desire +# NONE, SOME, FULL +OPTIMIZE= + +# specify any preprocessor symbols to be defined. The symbols will not +# have their values set automatically; you must supply the value (if any) +# to use. For example, setting DEFINES to "DEBUG=1" will cause the +# compiler option "-DDEBUG=1" to be used. Setting DEFINES to "DEBUG" +# would pass "-DDEBUG" on the compiler's command line. +DEFINES= + +# specify special warning levels +# if unspecified default warnings will be used +# NONE = supress all warnings +# ALL = enable all warnings +WARNINGS = + +# specify whether image symbols will be created +# so that stack crawls in the debugger are meaningful +# if TRUE symbols will be created +SYMBOLS = + +# specify debug settings +# if TRUE will allow application to be run from a source-level +# debugger. Note that this will disable all optimzation. +DEBUGGER = + +# specify additional compiler flags for all files +COMPILER_FLAGS = + +# specify additional linker flags +LINKER_FLAGS = + +# specify the version of this particular item +# (for example, -app 3 4 0 d 0 -short 340 -long "340 "`echo -n -e '\302\251'`"1999 GNU GPL") +# This may also be specified in a resource. +APP_VERSION = + +# (for TYPE == DRIVER only) Specify desired location of driver in the /dev +# hierarchy. Used by the driverinstall rule. E.g., DRIVER_PATH = video/usb will +# instruct the driverinstall rule to place a symlink to your driver's binary in +# ~/add-ons/kernel/drivers/dev/video/usb, so that your driver will appear at +# /dev/video/usb when loaded. Default is "misc". +DRIVER_PATH = + +## include the makefile-engine +include $(BUILDHOME)/etc/makefile-engine diff --git a/src/apps/autoraise/settings.cpp b/src/apps/autoraise/settings.cpp new file mode 100644 index 0000000000..852147d98d --- /dev/null +++ b/src/apps/autoraise/settings.cpp @@ -0,0 +1,85 @@ +#include "settings.h" +#include + +#define CONF_ADDPROP(_type, _name) \ +void AutoRaiseSettings::Set##_name(_type value)\ +{\ + _conf##_name = value;\ +}\ +\ +_type AutoRaiseSettings::##_name()\ +{\ + return _conf##_name;\ +}\ + + +CONF_ADDPROP(bool, Active) +CONF_ADDPROP(bigtime_t, Delay) +CONF_ADDPROP(int32, Mode) +//CONF_ADDPROP(BPath, AppPath) +CONF_ADDPROP(entry_ref, AppPath) +#undef CONF_ADDPROP + +AutoRaiseSettings::AutoRaiseSettings() +{ + _confActive = false; + _confDelay = DEFAULT_DELAY; + _confMode = Mode_All; + BPath prefPath; + + find_directory(B_USER_SETTINGS_DIRECTORY, &prefPath); + prefPath.Append(SETTINGS_FILE); + + _settingsFile.SetTo(prefPath.Path(), B_READ_WRITE | B_CREATE_FILE); + + if (_settingsMessage.Unflatten(&_settingsFile) == B_OK){ + + if (_settingsMessage.FindBool(AR_ACTIVE, &_confActive) != B_OK) + printf("AutoRaiseSettings::AutoRaiseSettings();\tFailed to load active boolean from settings file. Using default\n"); + + if (_settingsMessage.FindInt64(AR_DELAY, &_confDelay) != B_OK) + printf("AutoRaiseSettings::AutoRaiseSettings();\tFailed to load delay from settings file. Using default\n"); + + if (_settingsMessage.FindInt32(AR_MODE, &_confMode) != B_OK) + printf("AutoRaiseSettings::AutoRaiseSettings();\tFailed to load mode from settings file. Using default\n"); + +// if (_settingsMessage.FindFlat(AR_APP_PATH, (BFlattenable *) &_appPath) != B_OK) +// printf("AutoRaiseSettings::AutoRaiseSettings();\tFailed to load application path.\n"); + + if (_settingsMessage.FindRef(AR_APP_PATH, &_confAppPath) != B_OK) + printf("AutoRaiseSettings::AutoRaiseSettings();\tFailed to load application path.\n"); + } + else + { + printf("AutoRaiseSettings::AutoRaiseSettings()\nUnable to open settings file (either corrupted or doesn't exist), using defaults.\n"); + } + + _settingsFile.Unset(); +} + +AutoRaiseSettings::~AutoRaiseSettings() +{ + BPath prefPath; + find_directory(B_USER_SETTINGS_DIRECTORY, &prefPath); + prefPath.Append(SETTINGS_FILE); + + //clobber existing settings and write in new ones + _settingsFile.SetTo(prefPath.Path(), B_READ_WRITE | B_ERASE_FILE); + + + //empty message and refill it with whatever has been set + _settingsMessage.MakeEmpty(); + + _settingsMessage.AddBool(AR_ACTIVE, _confActive); + _settingsMessage.AddInt64(AR_DELAY, _confDelay); + _settingsMessage.AddInt32(AR_MODE, _confMode); +// _settingsMessage.AddFlat(AR_APP_PATH, &_appPath); + _settingsMessage.AddRef(AR_APP_PATH, &_confAppPath); + + //write message to settings file + if (_settingsMessage.Flatten(&_settingsFile) != B_OK) + printf("Error occurred writing settings\n"); + + _settingsFile.Unset(); +} + diff --git a/src/apps/autoraise/settings.h b/src/apps/autoraise/settings.h new file mode 100644 index 0000000000..9302b12931 --- /dev/null +++ b/src/apps/autoraise/settings.h @@ -0,0 +1,68 @@ +#ifndef SETTINGS_H +#define SETTINGS_H + + +/*************************************************** + settings.h + Mechanisms for managing the settings setting/retireval for AutoRaise + + 2002 mmu_man + from Deskscope: + 2000 Shamyl Zakariya +***************************************************/ +#include "common.h" + +/**************************************** + AutoRaiseSettings + Simple class for getting and setting prefs. + Instantiating will open up settings file + Destroying will write settings plus any changes + back into the file. + + Settings file won't be updated until AutoRaiseSettings + destructor is called. Doens't matter if it's allocated off + heap or stack. I recommend stack, though, to keep likelyhood + of race conditions down. + + File is defined in common.h as SETTINGS_FILE + +****************************************/ + +// make adding configuration fields easier +#define CONF_ADDPROP(_type, _name) \ +protected:\ + _type _conf##_name;\ +public:\ + void Set##_name(_type value);\ + _type _name(); + +class AutoRaiseSettings +{ + protected: + BFile _settingsFile; +// BPath _appPath; + + BMessage _settingsMessage; + + + + BMessage openSettingsFile(); + void closeSettingsFile(); + + public: + AutoRaiseSettings(); + ~AutoRaiseSettings(); + +CONF_ADDPROP(bool, Active) +CONF_ADDPROP(bigtime_t, Delay) +CONF_ADDPROP(int32, Mode) +//CONF_ADDPROP(BPath, AppPath) +CONF_ADDPROP(entry_ref, AppPath) + +}; + +#undef CONF_ADDPROP + +#define AR_APP_PATH "ar:app_path" + +#endif