Skip to content

Commit

Permalink
[Win32] Implement native menu - basics
Browse files Browse the repository at this point in the history
  • Loading branch information
milani committed Nov 2, 2012
1 parent e2ef58b commit a89f68f
Show file tree
Hide file tree
Showing 10 changed files with 134 additions and 11 deletions.
2 changes: 2 additions & 0 deletions binding.gyp
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,8 @@
'sources': [
'src/includes/util_win.cpp',
'src/native_window/native_window_win.cpp',
'src/native_menu/native_menu_win.cpp',
'src/native_status_icon/native_status_icon_win.cpp'
],
'defines': [
'__WIN__',
Expand Down
4 changes: 2 additions & 2 deletions src/appjs_app.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ Persistent<Function> App::constructor;
void App::Init() {
DECLARE_CONSTRUCTOR("App");
DECLARE_PROTOTYPE_METHOD("createWindow",CreateWindow2);
DECLARE_PROTOTYPE_METHOD("createMenu",CreateMenu);
DECLARE_PROTOTYPE_METHOD("createMenu",CreateMenu2);
DECLARE_PROTOTYPE_METHOD("createStatusIcon",CreateStatusIcon);
DECLARE_CLASS_FUNCTION(screenWidth, ScreenWidth);
DECLARE_CLASS_FUNCTION(screenHeight, ScreenHeight);
Expand Down Expand Up @@ -51,7 +51,7 @@ v8::Handle<Value> App::CreateWindow2(const Arguments& args) {
return scope.Close(Window::NewInstance(args));
}

v8::Handle<Value> App::CreateMenu(const Arguments& args) {
v8::Handle<Value> App::CreateMenu2(const Arguments& args) {
v8::HandleScope scope;
return scope.Close(Menu::NewInstance(args));
}
Expand Down
2 changes: 1 addition & 1 deletion src/appjs_app.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ class App : public node::ObjectWrap {
DEFINE_CLASS_FUNCTION(ScreenWidth);
DEFINE_CLASS_FUNCTION(ScreenHeight);
DEFINE_PROTOTYPE_METHOD(CreateWindow2);
DEFINE_PROTOTYPE_METHOD(CreateMenu);
DEFINE_PROTOTYPE_METHOD(CreateMenu2);
DEFINE_PROTOTYPE_METHOD(CreateStatusIcon);

static bool initialized_;
Expand Down
6 changes: 6 additions & 0 deletions src/native_menu/native_menu.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ class NativeMenu {
#elif defined(__MAC__)
int AddSubMenu(NSMenu*,Settings*);
bool Attach(NSMenu*);
#elif defined(__WIN__)
int AddSubMenu(HMENU&,Settings*);
bool Attach(HMENU&);
#endif

private:
Expand All @@ -46,6 +49,9 @@ class NativeMenu {
#elif defined(__MAC__)
NSArray* menuItems_;
#endif
#ifdef __WIN__
HMENU menu_;
#endif

};

Expand Down
83 changes: 83 additions & 0 deletions src/native_menu/native_menu_win.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
#include <node.h>
#include <windows.h>
#include <algorithm>
#define min(left,right) std::min(left,right)
#define max(left,right) std::max(left,right)
#include <gdiplus.h>
#include "appjs.h"
#include "includes/cef.h"
Expand All @@ -14,5 +17,85 @@ namespace appjs {

using namespace v8;

void NativeMenu::Init(Settings* settings) {
HMENU menu = CreateMenu();

MENUINFO menuInfo;
memset(&menuInfo, 0, sizeof(menuInfo));
menuInfo.cbSize = sizeof(menuInfo);
menuInfo.fMask = MIM_STYLE;
menuInfo.dwStyle = MNS_NOTIFYBYPOS;
SetMenuInfo(menu,&menuInfo);
AddSubMenu(menu,settings);
menu_ = menu;
}

int NativeMenu::AddSubMenu(HMENU& menu,Settings* settings){
int length = settings->getInteger("length",0);

Settings* item;
TCHAR* label;
TCHAR* icon;
appjs_action_callback* actionCb;

for( int i = 0; i < length; i++ ) {

item = new Settings( settings->getObject( i ) );
label = item->getString("label",TEXT(""));
icon = item->getString("icon",TEXT(""));
actionCb = new appjs_action_callback();
actionCb->action = Persistent<Object>::New( item->getObject("action") );
actionCb->item = Persistent<Object>::New( settings->getObject( i ) );
actionCb->menu = this;

Settings* subsettings = new Settings(item->getObject("submenu"));
HMENU submenu = CreateMenu();
if(AddSubMenu(submenu,subsettings)) { // has submenu
MENUINFO menuInfo;
memset(&menuInfo, 0, sizeof(menuInfo));
menuInfo.cbSize = sizeof(menuInfo);
menuInfo.fMask = MIM_STYLE;
menuInfo.dwStyle = MNS_NOTIFYBYPOS;
SetMenuInfo(submenu,&menuInfo);
AppendMenu(menu,MF_POPUP,(UINT)submenu,label);
} else { // does not have submenu
MENUITEMINFO menuItemInfo;
menuItemInfo.cbSize = sizeof(MENUITEMINFO);
menuItemInfo.fMask = MIIM_DATA;
menuItemInfo.dwTypeData = label;
menuItemInfo.dwItemData =(ULONG_PTR) actionCb;

if( wcslen(label) == 0 ) {
menuItemInfo.fType = MIIM_TYPE;
menuItemInfo.fType = MF_SEPARATOR;
} else {
menuItemInfo.fMask |= MIIM_STRING;
if(item->has("icon")) {
menuItemInfo.fMask |= MIIM_BITMAP;
HBITMAP bitmap;
Gdiplus::Color color;
Gdiplus::Bitmap* img = Gdiplus::Bitmap::FromFile(icon);
img->GetHBITMAP(color, &bitmap);
menuItemInfo.hbmpItem = bitmap;
}
}
InsertMenuItem(menu,i,false,&menuItemInfo);
}
}

return length;
}

bool NativeMenu::Attach(HMENU& menuBar) {
if(!attached_) {
menuBar = menu_;
attached_ = true;
this->Emit("attached");
return true;
} else {
// already attached
return false;
}
}

} /* appjs */
2 changes: 2 additions & 0 deletions src/native_status_icon/native_status_icon.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ class NativeStatusIcon {
#ifdef __MAC__
NSStatusItem* statusIconHandle_;
#endif
#ifdef __WIN__
#endif
};

} /* appjs */
Expand Down
8 changes: 8 additions & 0 deletions src/native_status_icon/native_status_icon_win.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,12 @@ void NativeStatusIcon::Init(Settings* settings) {

}

void NativeStatusIcon::Show(){
this->Emit("show");
}

void NativeStatusIcon::Hide(){
this->Emit("hide");
}

} /* appjs */
12 changes: 6 additions & 6 deletions src/native_window/native_window.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -235,23 +235,23 @@ appjs_rect NativeWindow::GetRect() {
return rect_;
}

void NativeWindow::Emit(v8::Handle<Value>* args){
void NativeWindow::Emit(v8::Handle<Value>* args,int length = 1){
if (!closed_) {
node::MakeCallback(v8handle_, "emit", ARRAY_SIZE(args), args);
node::MakeCallback(v8handle_, "emit", length, args);
}
}

void NativeWindow::Emit(const char* event){
v8::Handle<Value> args[1] = { String::New(event) };
Emit(args);
Emit(args,1);
}

void NativeWindow::Emit(const char* event, v8::Handle<Value> arg){
v8::Handle<Value> args[2] = {
String::New(event),
arg
};
Emit(args);
Emit(args,2);
}

void NativeWindow::Emit(const char* event, v8::Handle<Value> arg1, v8::Handle<Value> arg2){
Expand All @@ -260,7 +260,7 @@ void NativeWindow::Emit(const char* event, v8::Handle<Value> arg1, v8::Handle<Va
arg1,
arg2
};
Emit(args);
Emit(args,3);
}

void NativeWindow::Emit(const char* event, int arg1, int arg2){
Expand All @@ -269,7 +269,7 @@ void NativeWindow::Emit(const char* event, int arg1, int arg2){
Integer::New(arg1),
Integer::New(arg2)
};
Emit(args);
Emit(args,3);
}

void NativeWindow::Emit(const char* event, const int arg1, const int arg2, const int arg3){
Expand Down
2 changes: 1 addition & 1 deletion src/native_window/native_window.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ class NativeWindow {
static NativeWindow* GetWindow(CefRefPtr<CefBrowser> browser);

void SetIcon(NW_ICONSIZE size, TCHAR* path);
void Emit(v8::Handle<v8::Value>* args);
void Emit(v8::Handle<v8::Value>* args,int length);
void Emit(const char* event);
void Emit(const char* event, v8::Handle<v8::Value> arg);
void Emit(const char* event, v8::Handle<v8::Value> arg1, v8::Handle<v8::Value> arg2);
Expand Down
24 changes: 23 additions & 1 deletion src/native_window/native_window_win.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -475,6 +475,26 @@ LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
EndPaint(hwnd, &ps);
return 0;
}
case WM_MENUCOMMAND: {
HMENU menu = (HMENU)lParam;
MENUITEMINFO menuItem;
menuItem.cbSize = sizeof(MENUITEMINFO);
menuItem.fMask = MIIM_DATA;
int idx = wParam;
GetMenuItemInfo(menu,idx,TRUE,&menuItem);
appjs_action_callback* actionCallback = (appjs_action_callback*) menuItem.dwItemData;
Persistent<Object> action = actionCallback->action;
NativeMenu* nativeMenu = actionCallback->menu;

if(action->IsCallable()) {
const int argc = 1;
Handle<Value> argv[argc] = {actionCallback->item};
action->CallAsFunction(nativeMenu->GetV8Handle(),argc,argv);
}

nativeMenu->Emit("select",Local<Object>::New(actionCallback->item));
return 0;
}
case WM_SETFOCUS:
if (browser.get()) {
PostMessage(browser->GetWindowHandle(), WM_SETFOCUS, wParam, NULL);
Expand Down Expand Up @@ -566,7 +586,9 @@ int CALLBACK DirectorySelectHook(HWND hwnd, UINT msg, LPARAM lParam, LPARAM data
}

void NativeWindow::SetMenuBar(NativeMenu* nativeMenu) {

HMENU menu;
nativeMenu->Attach(menu);
SetMenu(handle_,menu);
}

void NativeWindow::OpenFileDialog(uv_work_t* req) {
Expand Down

0 comments on commit a89f68f

Please sign in to comment.