Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

[Linux] Basic status icon implementation

  • Loading branch information...
commit 1e1a23dc5bff4eb08e44fdfd6fb06902754c094f 1 parent a97185c
@milani milani authored
View
5 binding.gyp
@@ -243,8 +243,10 @@
'src/appjs_app.cpp',
'src/appjs_window.cpp',
'src/appjs_menu.cpp',
+ 'src/appjs_status_icon.cpp',
'src/native_window/native_window.cpp',
'src/native_menu/native_menu.cpp',
+ 'src/native_status_icon/native_status_icon.cpp',
'src/includes/cef_handler.cpp',
'src/includes/cef.cpp',
'src/includes/cef_loop.cpp',
@@ -288,7 +290,8 @@
['OS=="linux"', {
'sources': [
'src/native_window/native_window_linux.cpp',
- 'src/native_menu/native_menu_linux.cpp'
+ 'src/native_menu/native_menu_linux.cpp',
+ 'src/native_status_icon/native_status_icon_linux.cpp'
],
'defines': [
'__LINUX__',
View
32 lib/App.js
@@ -1,11 +1,12 @@
-var EventEmitter = require('events').EventEmitter,
- Router = require('./router').Router,
- Window = require('./window'),
- _App = require('./bindings').App,
- NativeWindow = require('./bindings').NativeWindow,
- NativeMenu = require('./bindings').NativeMenu,
- WindowSettings = require('./settings').WindowSettings,
- AppSettings = require('./settings').AppSettings;
+var EventEmitter = require('events').EventEmitter,
+ Router = require('./router').Router,
+ Window = require('./window'),
+ _App = require('./bindings').App,
+ NativeWindow = require('./bindings').NativeWindow,
+ NativeMenu = require('./bindings').NativeMenu,
+ NativeStatusIcon = require('./bindings').NativeStatusIcon,
+ WindowSettings = require('./settings').WindowSettings,
+ AppSettings = require('./settings').AppSettings;
var _init = require('./bindings').init,
decorate = require('./utils').decorate,
@@ -46,6 +47,16 @@ inherit(App, EventEmitter, [
]);
return nativeMenu;
},
+ function createStatusIcon(options){
+ var self = this,
+ nativeStatusIcon = new NativeStatusIcon(options);
+ inherit(nativeStatusIcon, EventEmitter, [
+ function toString(){
+ return '[object StatusIcon]';
+ }
+ ]);
+ return nativeStatusIcon;
+ },
function createWindow(url, options){
if (!this.settings) {
this.init();
@@ -106,8 +117,9 @@ inherit(App, EventEmitter, [
]);
-NativeMenu.prototype.__proto__ = process.EventEmitter.prototype;
-NativeWindow.prototype.__proto__ = process.EventEmitter.prototype;
+NativeMenu.prototype.__proto__ = process.EventEmitter.prototype;
+NativeWindow.prototype.__proto__ = process.EventEmitter.prototype;
+NativeStatusIcon.prototype.__proto__ = process.EventEmitter.prototype;
decorate(NativeWindow.prototype, [
function pipe(event, target){
View
2  src/appjs.cpp
@@ -15,11 +15,13 @@ void Init(Handle<v8::Object> target) {
App::Init();
Window::Init();
Menu::Init();
+ StatusIcon::Init();
target->Set(String::NewSymbol("init"), FunctionTemplate::New(InitApp)->GetFunction());
target->Set(String::NewSymbol("App"), App::constructor);
target->Set(String::NewSymbol("NativeWindow"), Window::constructor);
target->Set(String::NewSymbol("NativeMenu"), Menu::constructor);
+ target->Set(String::NewSymbol("NativeStatusIcon"), StatusIcon::constructor);
}
} /* appjs */
View
7 src/appjs_app.cpp
@@ -3,6 +3,7 @@
#include "appjs_app.h"
#include "appjs_window.h"
#include "appjs_menu.h"
+#include "appjs_status_icon.h"
#include "includes/cef.h"
#include "includes/util.h"
@@ -20,6 +21,7 @@ void App::Init() {
DECLARE_CONSTRUCTOR("App");
DECLARE_PROTOTYPE_METHOD("createWindow",CreateWindow2);
DECLARE_PROTOTYPE_METHOD("createMenu",CreateMenu);
+ DECLARE_PROTOTYPE_METHOD("createStatusIcon",CreateStatusIcon);
DECLARE_CLASS_FUNCTION(screenWidth, ScreenWidth);
DECLARE_CLASS_FUNCTION(screenHeight, ScreenHeight);
END_CONSTRUCTOR();
@@ -54,6 +56,11 @@ Handle<Value> App::CreateMenu(const Arguments& args) {
return scope.Close(Menu::NewInstance(args));
}
+Handle<Value> App::CreateStatusIcon(const Arguments& args) {
+ HandleScope scope;
+ return scope.Close(StatusIcon::NewInstance(args));
+}
+
Handle<Value> App::ScreenWidth(const Arguments& args) {
HandleScope scope;
Handle<Value> width = Integer::New(NativeWindow::ScreenWidth());
View
2  src/appjs_app.h
@@ -5,6 +5,7 @@
#include "appjs.h"
#include "appjs_window.h"
#include "appjs_menu.h"
+#include "appjs_status_icon.h"
namespace appjs {
@@ -16,6 +17,7 @@ class App : public node::ObjectWrap {
DEFINE_CLASS_FUNCTION(ScreenHeight);
DEFINE_PROTOTYPE_METHOD(CreateWindow2);
DEFINE_PROTOTYPE_METHOD(CreateMenu);
+ DEFINE_PROTOTYPE_METHOD(CreateStatusIcon);
static bool initialized_;
};
View
48 src/appjs_status_icon.cpp
@@ -0,0 +1,48 @@
+#include <node.h>
+#include "appjs.h"
+#include "appjs_status_icon.h"
+#include "includes/cef_handler.h"
+#include "includes/util.h"
+
+extern CefRefPtr<ClientHandler> g_handler;
+
+namespace appjs {
+
+using namespace v8;
+
+StatusIcon::StatusIcon(){}
+StatusIcon::~StatusIcon(){}
+
+Persistent<Function> StatusIcon::constructor;
+
+void StatusIcon::Init() {
+ DECLARE_CONSTRUCTOR("NativeStatusIcon");
+ DECLARE_PROTOTYPE_METHOD("show",Show);
+ DECLARE_PROTOTYPE_METHOD("hide",Hide);
+ END_CONSTRUCTOR();
+}
+
+Handle<Value> StatusIcon::New(const Arguments& args) {
+ HandleScope scope;
+
+ Persistent<Object> options = Persistent<Object>::New(args[0]->ToObject());
+ Settings* settings = new Settings(options);
+ NativeStatusIcon* statusIcon = new NativeStatusIcon(settings);
+
+ Persistent<Object> self = Persistent<Object>::New(args.This());
+ statusIcon->SetV8Handle(self);
+ self->SetPointerInInternalField(0, statusIcon);
+
+ return scope.Close(args.This());
+}
+
+Handle<Value> StatusIcon::NewInstance(const Arguments& args) {
+ HandleScope scope;
+ Handle<Value> argv[1] = { args[0] };
+ return scope.Close(constructor->NewInstance(1, argv));
+}
+
+CREATE_PROTOTYPE_INVOKER(StatusIcon, Show)
+CREATE_PROTOTYPE_INVOKER(StatusIcon, Hide)
+
+} /* appjs */
View
19 src/appjs_status_icon.h
@@ -0,0 +1,19 @@
+#ifndef APPJS_STATUS_ICON_H
+#define APPJS_STATUS_ICON_H
+#pragma once
+
+#include "appjs.h"
+#include "native_status_icon/native_status_icon.h"
+
+namespace appjs {
+
+using namespace v8;
+
+class StatusIcon : public node::ObjectWrap {
+ DEFINE_OBJECT_FACTORY(StatusIcon);
+ DEFINE_PROTOTYPE_METHOD(Show);
+ DEFINE_PROTOTYPE_METHOD(Hide);
+};
+
+} /* appjs */
+#endif /* end of APPJS_STATUS_ICON_H */
View
43 src/appjs_tray.cpp
@@ -1,43 +0,0 @@
-#include <node.h>
-#include "appjs.h"
-#include "appjs_tray.h"
-#include "includes/cef_handler.h"
-#include "includes/util.h"
-
-extern CefRefPtr<ClientHandler> g_handler;
-
-namespace appjs {
-
-using namespace v8;
-
-Tray::Tray(){}
-Tray::~Tray(){}
-
-Persistent<Function> Tray::constructor;
-
-void Tray::Init() {
- DECLARE_CONSTRUCTOR("NativeTray");
- END_CONSTRUCTOR();
-}
-
-Handle<Value> Tray::New(const Arguments& args) {
- HandleScope scope;
-
- Persistent<Object> options = Persistent<Object>::New(args[0]->ToObject());
- Settings* settings = new Settings(options);
- NativeTray* window = new NativeTray(settings);
-
- Persistent<Object> self = Persistent<Object>::New(args.This());
- tray->SetV8Handle(self);
- self->SetPointerInInternalField(0, tray);
-
- return scope.Close(args.This());
-}
-
-Handle<Value> Tray::NewInstance(const Arguments& args) {
- HandleScope scope;
- Handle<Value> argv[1] = { args[0] };
- return scope.Close(constructor->NewInstance(1, argv));
-}
-
-} /* appjs */
View
17 src/appjs_tray.h
@@ -1,17 +0,0 @@
-#ifndef APPJS_TRAY_H
-#define APPJS_TRAY_H
-#pragma once
-
-#include "appjs.h"
-#include "native_tray/native_tray.h"
-
-namespace appjs {
-
-using namespace v8;
-
-class Tray : public node::ObjectWrap {
- DEFINE_OBJECT_FACTORY(Tray);
-};
-
-} /* appjs */
-#endif /* end of APPJS_TRAY_H */
View
10 src/includes/util.h
@@ -27,12 +27,12 @@ class Settings {
Settings(v8::Local<v8::Object>);
~Settings(){settings_.Dispose();}
- bool isNull(const char*);
- bool has(const char*);
+ bool isNull(const char*);
+ bool has(const char*);
double getNumber(const char*, double);
- int getInteger(const char*, int);
- bool getBoolean(const char*,bool);
- char* getString(const char*, char*);
+ int getInteger(const char*, int);
+ bool getBoolean(const char*,bool);
+ char* getString(const char*, char*);
#ifdef __WIN__
TCHAR* getString(const char*,TCHAR*);
View
1  src/native_menu/native_menu.cpp
@@ -9,6 +9,7 @@ namespace appjs {
using namespace v8;
NativeMenu::NativeMenu(Settings* settings){
+ attached_ = false;
Init(settings);
}
View
6 src/native_menu/native_menu.h
@@ -24,16 +24,18 @@ class NativeMenu {
void SetV8Handle(v8::Handle<v8::Object> v8handle) {v8handle_ = v8handle;};
v8::Handle<v8::Object> GetV8Handle() {return v8handle_;};
#ifdef __LINUX__
- std::vector<GtkWidget*> GetMenu() {return menuItems_;};
int AddSubMenu(GtkWidget*,Settings*);
-#endif
+ bool Attach(GtkMenuShell*);
+#endif
private:
v8::Handle<v8::Object> v8handle_;
+ bool attached_;
#ifdef __LINUX__
//GtkWidget* menu_;
std::vector<GtkWidget*> menuItems_;
+ GtkMenuShell* menu_;
#endif
};
View
19 src/native_menu/native_menu_linux.cpp
@@ -96,4 +96,21 @@ int NativeMenu::AddSubMenu(GtkWidget* menu,Settings* settings){
}
-} /* appjs */
+bool NativeMenu::Attach(GtkMenuShell* menuBar) {
+ if(!attached_) {
+ menu_ = menuBar;
+
+ for(std::vector<GtkWidget*>::iterator it = menuItems_.begin(); it != menuItems_.end(); ++it) {
+ gtk_menu_shell_append(menuBar,(*it));
+ }
+
+ this->Emit("attached");
+
+ return true;
+ } else {
+ // already attached
+ return false;
+ }
+}
+
+} /* appjs */
View
37 src/native_status_icon/native_status_icon.cpp
@@ -0,0 +1,37 @@
+#include "includes/cef.h"
+#include "includes/cef_handler.h"
+#include "native_status_icon/native_status_icon.h"
+
+extern CefRefPtr<ClientHandler> g_handler;
+
+namespace appjs {
+
+using namespace v8;
+
+NativeStatusIcon::NativeStatusIcon(Settings* settings){
+ Init(settings);
+}
+
+NativeStatusIcon::~NativeStatusIcon(){
+}
+
+void NativeStatusIcon::Emit(Handle<Value>* args,int length){
+ node::MakeCallback(v8handle_, "emit", length, args);
+}
+
+void NativeStatusIcon::Emit(const char* event){
+ Handle<Value> args[1] = { String::New(event) };
+ Emit(args,1);
+}
+
+void NativeStatusIcon::Emit(const char* event, Handle<Value> arg){
+
+ Handle<Value> args[2] = {
+ String::New(event),
+ arg
+ };
+
+ Emit(args,2);
+}
+
+} /* appjs */
View
36 src/native_status_icon/native_status_icon.h
@@ -0,0 +1,36 @@
+#ifndef APPJS_BASE_NATIVE_STATUS_ICON_H
+#define APPJS_BASE_NATIVE_STATUS_ICON_H
+#pragma once
+
+#include "appjs.h"
+#include "include/cef_browser.h"
+#include "includes/util.h"
+#include "native_status_icon/native_status_icon.h"
+#include <node.h>
+
+namespace appjs {
+
+class NativeStatusIcon {
+
+public:
+ NativeStatusIcon(Settings* settings);
+ ~NativeStatusIcon();
+ void Init(Settings* settings);
+ void Show();
+ void Hide();
+
+ void Emit(v8::Handle<v8::Value>* args,int);
+ void Emit(const char* event);
+ void Emit(const char* event, v8::Handle<v8::Value> arg);
+
+ void SetV8Handle(v8::Handle<v8::Object> v8handle) {v8handle_ = v8handle;};
+ v8::Handle<v8::Object> GetV8Handle() {return v8handle_;};
+
+private:
+ v8::Handle<v8::Object> v8handle_;
+ GtkStatusIcon* statusIconHandle_;
+};
+
+} /* appjs */
+
+#endif /* end of APPJS_BASE_NATIVE_STATUS_ICON_H */
View
80 src/native_status_icon/native_status_icon_linux.cpp
@@ -0,0 +1,80 @@
+#include <node.h>
+#include <gtk/gtk.h>
+#include <vector>
+
+#include "appjs.h"
+#include "native_status_icon/native_status_icon.h"
+#include "includes/cef.h"
+#include "includes/util.h"
+#include "includes/cef_handler.h"
+
+extern CefRefPtr<ClientHandler> g_handler;
+
+namespace appjs {
+
+using namespace v8;
+
+void status_icon_show_menu(GtkWidget* statusIcon,guint button, guint32 activate_time,GtkMenu* menu) {
+ gtk_menu_popup(menu, NULL, NULL, gtk_status_icon_position_menu, statusIcon, button, activate_time);
+}
+
+void status_icon_click(GtkWidget* statusIcon,NativeStatusIcon* me) {
+ me->Emit("click");
+}
+
+void status_icon_popup(GtkWidget* statusIcon,guint button, guint32 activate_time,NativeStatusIcon* me) {
+ me->Emit("popup");
+}
+
+void NativeStatusIcon::Init(Settings* settings) {
+ char* iconFile = settings->getString("icon","");
+ char* tooltip = settings->getString("tooltip","");
+ bool visible = settings->getBoolean("visible",true);
+
+ // TODO local or persistent?
+ Local<Object> menu = settings->getObject("menu");
+
+ NativeMenu* nativeMenu;
+ GtkStatusIcon *statusIcon;
+
+ if( settings->has("icon") ) {
+ statusIcon = gtk_status_icon_new_from_file(iconFile);
+ } else {
+ statusIcon = gtk_status_icon_new_from_stock(GTK_STOCK_MISSING_IMAGE);
+ }
+
+ statusIconHandle_ = statusIcon;
+
+ if( settings->has("tooltip") ) {
+ gtk_status_icon_set_tooltip_text(statusIcon, tooltip);
+ gtk_status_icon_set_title(statusIcon,tooltip);
+ }
+
+ if( settings->has("menu") ) {
+
+ GtkWidget* gtkMenu = gtk_menu_new();
+
+ nativeMenu = (NativeMenu*)menu->GetPointerFromInternalField(0);
+ nativeMenu->Attach(GTK_MENU_SHELL(gtkMenu));
+
+ g_signal_connect(statusIcon, "popup-menu", GTK_SIGNAL_FUNC (status_icon_show_menu), gtkMenu);
+
+ }
+
+ g_signal_connect(statusIcon, "activate", G_CALLBACK(status_icon_click), this);
+ g_signal_connect(statusIcon, "popup-menu", G_CALLBACK(status_icon_popup), this);
+
+ gtk_status_icon_set_visible(statusIcon, visible);
+}
+
+void NativeStatusIcon::Show(){
+ gtk_status_icon_set_visible(statusIconHandle_, TRUE);
+ this->Emit("show");
+}
+
+void NativeStatusIcon::Hide(){
+ gtk_status_icon_set_visible(statusIconHandle_, FALSE);
+ this->Emit("hide");
+}
+
+} /* appjs */
View
20 src/native_status_icon/native_status_icon_mac.mm
@@ -0,0 +1,20 @@
+#import <Cocoa/Cocoa.h>
+#import <objc/runtime.h>
+#import "include/cef_application_mac.h"
+#include "appjs.h"
+#include "includes/cef.h"
+#include "includes/util.h"
+#include "includes/cef_handler.h"
+#include "native_status_icon/native_status_icon.h"
+
+// The global ClientHandler reference.
+extern CefRefPtr<ClientHandler> g_handler;
+
+namespace appjs {
+
+void NativeStatusIcon::Init(Settings* settings) {
+
+}
+
+} /* appjs */
+
View
26 src/native_status_icon/native_status_icon_win.cpp
@@ -0,0 +1,26 @@
+#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 <shlobj.h>
+#include <shlwapi.h>
+#include "appjs.h"
+#include "includes/cef.h"
+#include "includes/util.h"
+#include "includes/util_win.h"
+#include "includes/cef_handler.h"
+#include "native_status_icon/native_status_icon.h"
+
+extern CefRefPtr<ClientHandler> g_handler;
+
+namespace appjs {
+
+using namespace v8;
+
+void NativeStatusIcon::Init(Settings* settings) {
+
+}
+
+} /* appjs */
View
8 src/native_window/native_window_linux.cpp
@@ -207,16 +207,12 @@ NativeWindow* NativeWindow::GetWindow(CefRefPtr<CefBrowser> browser){
void NativeWindow::SetMenuBar(NativeMenu* nativeMenu) {
- std::vector<GtkWidget*> menuItems = nativeMenu->GetMenu();
-
GtkWidget* menu_bar = gtk_menu_bar_new ();
- for(std::vector<GtkWidget*>::iterator it = menuItems.begin(); it != menuItems.end(); ++it) {
- gtk_menu_bar_append(GTK_MENU_SHELL(menu_bar),(*it));
- }
+ nativeMenu->Attach(GTK_MENU_SHELL(menu_bar));
gtk_box_pack_start(GTK_BOX (gtk_bin_get_child(GTK_BIN(handle_))), menu_bar, FALSE, FALSE, 0);
gtk_box_reorder_child(GTK_BOX (gtk_bin_get_child(GTK_BIN(handle_))),menu_bar,0);
- gtk_widget_show (menu_bar);
+ gtk_widget_show(menu_bar);
}
Please sign in to comment.
Something went wrong with that request. Please try again.