mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 15:28:11 +00:00
Start working on a Downloader app and backing classes in LibGUI.
LibGUI is slowly becoming LibKitchensink but I'm okay with this for now.
This commit is contained in:
parent
c7365a00f8
commit
8f30657390
21 changed files with 375 additions and 1 deletions
3
Applications/Downloader/.gitignore
vendored
Normal file
3
Applications/Downloader/.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
*.o
|
||||||
|
*.d
|
||||||
|
Downloader
|
32
Applications/Downloader/Makefile
Normal file
32
Applications/Downloader/Makefile
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
OBJS = \
|
||||||
|
main.o
|
||||||
|
|
||||||
|
APP = Downloader
|
||||||
|
|
||||||
|
STANDARD_FLAGS = -std=c++17 -Wno-sized-deallocation
|
||||||
|
WARNING_FLAGS = -Wextra -Wall -Wundef -Wcast-qual -Wwrite-strings -Wimplicit-fallthrough
|
||||||
|
FLAVOR_FLAGS = -fno-exceptions -fno-rtti
|
||||||
|
OPTIMIZATION_FLAGS = -Os
|
||||||
|
INCLUDE_FLAGS = -I../../Servers -I../.. -I. -I../../LibC
|
||||||
|
|
||||||
|
DEFINES = -DSERENITY -DSANITIZE_PTRS -DUSERLAND
|
||||||
|
|
||||||
|
CXXFLAGS = -MMD -MP $(WARNING_FLAGS) $(OPTIMIZATION_FLAGS) $(FLAVOR_FLAGS) $(STANDARD_FLAGS) $(INCLUDE_FLAGS) $(DEFINES)
|
||||||
|
CXX = i686-pc-serenity-g++
|
||||||
|
LD = i686-pc-serenity-g++
|
||||||
|
AR = i686-pc-serenity-ar
|
||||||
|
LDFLAGS = -L../../LibC -L../../LibGUI
|
||||||
|
|
||||||
|
all: $(APP)
|
||||||
|
|
||||||
|
$(APP): $(OBJS)
|
||||||
|
$(LD) -o $(APP) $(LDFLAGS) $(OBJS) -lgui -lc
|
||||||
|
|
||||||
|
.cpp.o:
|
||||||
|
@echo "CXX $<"; $(CXX) $(CXXFLAGS) -o $@ -c $<
|
||||||
|
|
||||||
|
-include $(OBJS:%.o=%.d)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
@echo "CLEAN"; rm -f $(APPS) $(OBJS) *.d
|
||||||
|
|
30
Applications/Downloader/main.cpp
Normal file
30
Applications/Downloader/main.cpp
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
#include <LibGUI/GApplication.h>
|
||||||
|
#include <LibGUI/GHttpRequest.h>
|
||||||
|
#include <LibGUI/GHttpResponse.h>
|
||||||
|
#include <LibGUI/GNetworkJob.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
int main(int argc, char** argv)
|
||||||
|
{
|
||||||
|
GApplication app(argc, argv);
|
||||||
|
|
||||||
|
GHttpRequest request;
|
||||||
|
request.set_hostname("www.google.com");
|
||||||
|
request.set_path("/");
|
||||||
|
|
||||||
|
auto job = request.schedule();
|
||||||
|
job->on_finish = [&job] (bool success) {
|
||||||
|
if (!success) {
|
||||||
|
dbgprintf("on_finish: request failed :(\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto& response = static_cast<const GHttpResponse&>(*job->response());
|
||||||
|
printf("on_receive: code=%d\n", response.code());
|
||||||
|
printf("payload:\n");
|
||||||
|
printf("%s", response.payload().pointer());
|
||||||
|
printf("payload was %d bytes\n", response.payload().size());
|
||||||
|
};
|
||||||
|
|
||||||
|
printf("Entering main loop...\n");
|
||||||
|
return app.exec();
|
||||||
|
}
|
|
@ -36,6 +36,8 @@ $make_cmd -C ../Applications/IRCClient clean && \
|
||||||
$make_cmd -C ../Applications/IRCClient && \
|
$make_cmd -C ../Applications/IRCClient && \
|
||||||
$make_cmd -C ../Applications/Taskbar clean && \
|
$make_cmd -C ../Applications/Taskbar clean && \
|
||||||
$make_cmd -C ../Applications/Taskbar && \
|
$make_cmd -C ../Applications/Taskbar && \
|
||||||
|
$make_cmd -C ../Applications/Downloader clean && \
|
||||||
|
$make_cmd -C ../Applications/Downloader && \
|
||||||
$make_cmd clean &&\
|
$make_cmd clean &&\
|
||||||
$make_cmd && \
|
$make_cmd && \
|
||||||
sudo ./sync.sh
|
sudo ./sync.sh
|
||||||
|
|
|
@ -94,6 +94,8 @@ cp -v ../Servers/LookupServer/LookupServer mnt/bin/LookupServer
|
||||||
cp -v ../Servers/WindowServer/WindowServer mnt/bin/WindowServer
|
cp -v ../Servers/WindowServer/WindowServer mnt/bin/WindowServer
|
||||||
cp -v ../Applications/Taskbar/Taskbar mnt/bin/Taskbar
|
cp -v ../Applications/Taskbar/Taskbar mnt/bin/Taskbar
|
||||||
ln -s Taskbar mnt/bin/tb
|
ln -s Taskbar mnt/bin/tb
|
||||||
|
cp -v ../Applications/Downloader/Downloader mnt/bin/Downloader
|
||||||
|
ln -s Downloader mnt/bin/dl
|
||||||
cp -v kernel.map mnt/
|
cp -v kernel.map mnt/
|
||||||
sh sync-local.sh
|
sh sync-local.sh
|
||||||
umount mnt || ( sleep 0.5 && sync && umount mnt )
|
umount mnt || ( sleep 0.5 && sync && umount mnt )
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include <AK/AKString.h>
|
#include <AK/AKString.h>
|
||||||
#include <AK/Types.h>
|
#include <AK/Types.h>
|
||||||
#include <AK/WeakPtr.h>
|
#include <AK/WeakPtr.h>
|
||||||
|
#include <AK/Function.h>
|
||||||
#include <Kernel/KeyCode.h>
|
#include <Kernel/KeyCode.h>
|
||||||
#include <LibGUI/GWindowType.h>
|
#include <LibGUI/GWindowType.h>
|
||||||
|
|
||||||
|
@ -28,6 +29,7 @@ public:
|
||||||
KeyUp,
|
KeyUp,
|
||||||
Timer,
|
Timer,
|
||||||
DeferredDestroy,
|
DeferredDestroy,
|
||||||
|
DeferredInvoke,
|
||||||
WindowEntered,
|
WindowEntered,
|
||||||
WindowLeft,
|
WindowLeft,
|
||||||
WindowBecameInactive,
|
WindowBecameInactive,
|
||||||
|
@ -55,6 +57,19 @@ private:
|
||||||
Type m_type { Invalid };
|
Type m_type { Invalid };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class GDeferredInvocationEvent : public GEvent {
|
||||||
|
friend class GEventLoop;
|
||||||
|
public:
|
||||||
|
GDeferredInvocationEvent(Function<void(GObject&)> invokee)
|
||||||
|
: GEvent(GEvent::Type::DeferredInvoke)
|
||||||
|
, m_invokee(move(invokee))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Function<void(GObject&)> m_invokee;
|
||||||
|
};
|
||||||
|
|
||||||
class GWMEvent : public GEvent {
|
class GWMEvent : public GEvent {
|
||||||
public:
|
public:
|
||||||
GWMEvent(Type type, int client_id, int window_id)
|
GWMEvent(Type type, int client_id, int window_id)
|
||||||
|
|
|
@ -158,6 +158,9 @@ int GEventLoop::exec()
|
||||||
default:
|
default:
|
||||||
dbgprintf("Event type %u with no receiver :(\n", event.type());
|
dbgprintf("Event type %u with no receiver :(\n", event.type());
|
||||||
}
|
}
|
||||||
|
} else if (event.type() == GEvent::Type::DeferredInvoke) {
|
||||||
|
printf("DeferredInvoke: receiver=%s{%p}\n", receiver->class_name(), receiver);
|
||||||
|
static_cast<GDeferredInvocationEvent&>(event).m_invokee(*receiver);
|
||||||
} else {
|
} else {
|
||||||
receiver->event(event);
|
receiver->event(event);
|
||||||
}
|
}
|
||||||
|
|
47
LibGUI/GHttpNetworkJob.cpp
Normal file
47
LibGUI/GHttpNetworkJob.cpp
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
#include <LibGUI/GHttpNetworkJob.h>
|
||||||
|
#include <LibGUI/GHttpResponse.h>
|
||||||
|
#include <LibGUI/GTCPSocket.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
GHttpNetworkJob::GHttpNetworkJob(const GHttpRequest& request)
|
||||||
|
: m_request(request)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
GHttpNetworkJob::~GHttpNetworkJob()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void GHttpNetworkJob::start()
|
||||||
|
{
|
||||||
|
ASSERT(!m_socket);
|
||||||
|
m_socket = new GTCPSocket(this);
|
||||||
|
int success = m_socket->connect(m_request.hostname(), m_request.port());
|
||||||
|
if (!success)
|
||||||
|
return did_fail(GNetworkJob::Error::ConnectionFailed);
|
||||||
|
|
||||||
|
auto raw_request = m_request.to_raw_request();
|
||||||
|
|
||||||
|
printf("raw_request:\n%s\n", raw_request.pointer());
|
||||||
|
|
||||||
|
success = m_socket->send(raw_request);
|
||||||
|
if (!success)
|
||||||
|
return did_fail(GNetworkJob::Error::TransmissionFailed);
|
||||||
|
|
||||||
|
Vector<byte> buffer;
|
||||||
|
while (m_socket->is_connected()) {
|
||||||
|
auto payload = m_socket->receive(100000);
|
||||||
|
if (!payload) {
|
||||||
|
if (m_socket->eof())
|
||||||
|
break;
|
||||||
|
return did_fail(GNetworkJob::Error::TransmissionFailed);
|
||||||
|
}
|
||||||
|
buffer.append(payload.pointer(), payload.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
auto response = GHttpResponse::create(1, ByteBuffer::copy(buffer.data(), buffer.size()));
|
||||||
|
deferred_invoke([this, response] (GObject&) {
|
||||||
|
printf("in the deferred invoke lambda\n");
|
||||||
|
did_finish(move(response));
|
||||||
|
});
|
||||||
|
}
|
20
LibGUI/GHttpNetworkJob.h
Normal file
20
LibGUI/GHttpNetworkJob.h
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <LibGUI/GNetworkJob.h>
|
||||||
|
#include <LibGUI/GHttpRequest.h>
|
||||||
|
|
||||||
|
class GTCPSocket;
|
||||||
|
|
||||||
|
class GHttpNetworkJob final : public GNetworkJob {
|
||||||
|
public:
|
||||||
|
explicit GHttpNetworkJob(const GHttpRequest&);
|
||||||
|
virtual ~GHttpNetworkJob() override;
|
||||||
|
|
||||||
|
virtual void start() override;
|
||||||
|
|
||||||
|
virtual const char* class_name() const override { return "GHttpNetworkJob"; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
GHttpRequest m_request;
|
||||||
|
GTCPSocket* m_socket { nullptr };
|
||||||
|
};
|
45
LibGUI/GHttpRequest.cpp
Normal file
45
LibGUI/GHttpRequest.cpp
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
#include <LibGUI/GHttpRequest.h>
|
||||||
|
#include <LibGUI/GHttpNetworkJob.h>
|
||||||
|
#include <LibGUI/GEventLoop.h>
|
||||||
|
#include <AK/StringBuilder.h>
|
||||||
|
|
||||||
|
GHttpRequest::GHttpRequest()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
GHttpRequest::~GHttpRequest()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
GNetworkJob* GHttpRequest::schedule()
|
||||||
|
{
|
||||||
|
auto* job = new GHttpNetworkJob(*this);
|
||||||
|
job->start();
|
||||||
|
return job;
|
||||||
|
}
|
||||||
|
|
||||||
|
String GHttpRequest::method_name() const
|
||||||
|
{
|
||||||
|
switch (m_method) {
|
||||||
|
case Method::GET:
|
||||||
|
return "GET";
|
||||||
|
case Method::HEAD:
|
||||||
|
return "HEAD";
|
||||||
|
case Method::POST:
|
||||||
|
return "POST";
|
||||||
|
default:
|
||||||
|
ASSERT_NOT_REACHED();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteBuffer GHttpRequest::to_raw_request() const
|
||||||
|
{
|
||||||
|
StringBuilder builder;
|
||||||
|
builder.append(method_name());
|
||||||
|
builder.append(' ');
|
||||||
|
builder.append(m_path);
|
||||||
|
builder.append(" HTTP/1.0\nHost: ");
|
||||||
|
builder.append(m_hostname);
|
||||||
|
builder.append("\n\n");
|
||||||
|
return builder.to_byte_buffer();
|
||||||
|
}
|
34
LibGUI/GHttpRequest.h
Normal file
34
LibGUI/GHttpRequest.h
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <AK/AKString.h>
|
||||||
|
|
||||||
|
class GNetworkJob;
|
||||||
|
|
||||||
|
class GHttpRequest {
|
||||||
|
public:
|
||||||
|
enum Method { Invalid, HEAD, GET, POST };
|
||||||
|
|
||||||
|
GHttpRequest();
|
||||||
|
~GHttpRequest();
|
||||||
|
|
||||||
|
String hostname() const { return m_hostname; }
|
||||||
|
int port() const { return m_port; }
|
||||||
|
String path() const { return m_path; }
|
||||||
|
Method method() const { return m_method; }
|
||||||
|
|
||||||
|
void set_hostname(const String& hostname) { m_hostname = hostname; }
|
||||||
|
void set_port(int port) { m_port = port; }
|
||||||
|
void set_path(const String& path) { m_path = path; }
|
||||||
|
void set_method(Method method) { m_method = method; }
|
||||||
|
|
||||||
|
String method_name() const;
|
||||||
|
ByteBuffer to_raw_request() const;
|
||||||
|
|
||||||
|
GNetworkJob* schedule();
|
||||||
|
|
||||||
|
private:
|
||||||
|
String m_hostname;
|
||||||
|
String m_path;
|
||||||
|
int m_port { 80 };
|
||||||
|
Method m_method { GET };
|
||||||
|
};
|
11
LibGUI/GHttpResponse.cpp
Normal file
11
LibGUI/GHttpResponse.cpp
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
#include <LibGUI/GHttpResponse.h>
|
||||||
|
|
||||||
|
GHttpResponse::GHttpResponse(int code, ByteBuffer&& payload)
|
||||||
|
: GNetworkResponse(move(payload))
|
||||||
|
, m_code(code)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
GHttpResponse::~GHttpResponse()
|
||||||
|
{
|
||||||
|
}
|
23
LibGUI/GHttpResponse.h
Normal file
23
LibGUI/GHttpResponse.h
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <LibGUI/GNetworkResponse.h>
|
||||||
|
#include <AK/AKString.h>
|
||||||
|
#include <AK/HashMap.h>
|
||||||
|
|
||||||
|
class GHttpResponse : public GNetworkResponse {
|
||||||
|
public:
|
||||||
|
virtual ~GHttpResponse() override;
|
||||||
|
static Retained<GHttpResponse> create(int code, ByteBuffer&& payload)
|
||||||
|
{
|
||||||
|
return adopt(*new GHttpResponse(code, move(payload)));
|
||||||
|
}
|
||||||
|
|
||||||
|
int code() const { return m_code; }
|
||||||
|
const HashMap<String, String>& headers() const { return m_headers; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
GHttpResponse(int code, ByteBuffer&&);
|
||||||
|
|
||||||
|
int m_code { 0 };
|
||||||
|
HashMap<String, String> m_headers;
|
||||||
|
};
|
|
@ -42,6 +42,10 @@ ByteBuffer GIODevice::read(int max_size)
|
||||||
set_error(errno);
|
set_error(errno);
|
||||||
return { };
|
return { };
|
||||||
}
|
}
|
||||||
|
if (nread == 0) {
|
||||||
|
set_eof(true);
|
||||||
|
return { };
|
||||||
|
}
|
||||||
buffer.trim(nread);
|
buffer.trim(nread);
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
27
LibGUI/GNetworkJob.cpp
Normal file
27
LibGUI/GNetworkJob.cpp
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
#include <LibGUI/GNetworkJob.h>
|
||||||
|
#include <LibGUI/GNetworkResponse.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
GNetworkJob::GNetworkJob()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
GNetworkJob::~GNetworkJob()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void GNetworkJob::did_finish(Retained<GNetworkResponse>&& response)
|
||||||
|
{
|
||||||
|
m_response = move(response);
|
||||||
|
printf("%s{%p} job did_finish!\n", class_name(), this);
|
||||||
|
ASSERT(on_finish);
|
||||||
|
on_finish(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GNetworkJob::did_fail(Error error)
|
||||||
|
{
|
||||||
|
m_error = error;
|
||||||
|
dbgprintf("%s{%} job did_fail! error=%u\n", class_name(), this, (unsigned)error);
|
||||||
|
ASSERT(on_finish);
|
||||||
|
on_finish(false);
|
||||||
|
}
|
36
LibGUI/GNetworkJob.h
Normal file
36
LibGUI/GNetworkJob.h
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <LibGUI/GObject.h>
|
||||||
|
#include <AK/Function.h>
|
||||||
|
|
||||||
|
class GNetworkResponse;
|
||||||
|
|
||||||
|
class GNetworkJob : public GObject {
|
||||||
|
public:
|
||||||
|
enum class Error {
|
||||||
|
None,
|
||||||
|
ConnectionFailed,
|
||||||
|
TransmissionFailed,
|
||||||
|
};
|
||||||
|
virtual ~GNetworkJob() override;
|
||||||
|
|
||||||
|
Function<void(bool success)> on_finish;
|
||||||
|
|
||||||
|
bool has_error() const { return m_error != Error::None; }
|
||||||
|
Error error() const { return m_error; }
|
||||||
|
GNetworkResponse* response() { return m_response.ptr(); }
|
||||||
|
const GNetworkResponse* response() const { return m_response.ptr(); }
|
||||||
|
|
||||||
|
virtual void start() = 0;
|
||||||
|
|
||||||
|
virtual const char* class_name() const override { return "GNetworkJob"; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
GNetworkJob();
|
||||||
|
void did_finish(Retained<GNetworkResponse>&&);
|
||||||
|
void did_fail(Error);
|
||||||
|
|
||||||
|
private:
|
||||||
|
RetainPtr<GNetworkResponse> m_response;
|
||||||
|
Error m_error { Error::None };
|
||||||
|
};
|
10
LibGUI/GNetworkResponse.cpp
Normal file
10
LibGUI/GNetworkResponse.cpp
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
#include <LibGUI/GNetworkResponse.h>
|
||||||
|
|
||||||
|
GNetworkResponse::GNetworkResponse(ByteBuffer&& payload)
|
||||||
|
: m_payload(payload)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
GNetworkResponse::~GNetworkResponse()
|
||||||
|
{
|
||||||
|
}
|
18
LibGUI/GNetworkResponse.h
Normal file
18
LibGUI/GNetworkResponse.h
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <AK/Retainable.h>
|
||||||
|
#include <AK/ByteBuffer.h>
|
||||||
|
|
||||||
|
class GNetworkResponse : public Retainable<GNetworkResponse> {
|
||||||
|
public:
|
||||||
|
virtual ~GNetworkResponse();
|
||||||
|
|
||||||
|
bool is_error() const { return m_error; }
|
||||||
|
const ByteBuffer& payload() const { return m_payload; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
explicit GNetworkResponse(ByteBuffer&&);
|
||||||
|
|
||||||
|
bool m_error { false };
|
||||||
|
ByteBuffer m_payload;
|
||||||
|
};
|
|
@ -99,5 +99,9 @@ void GObject::dump_tree(int indent)
|
||||||
for (auto* child : children()) {
|
for (auto* child : children()) {
|
||||||
child->dump_tree(indent + 2);
|
child->dump_tree(indent + 2);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GObject::deferred_invoke(Function<void(GObject&)> invokee)
|
||||||
|
{
|
||||||
|
GEventLoop::current().post_event(*this, make<GDeferredInvocationEvent>(move(invokee)));
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <AK/Function.h>
|
||||||
#include <AK/Vector.h>
|
#include <AK/Vector.h>
|
||||||
#include <AK/Weakable.h>
|
#include <AK/Weakable.h>
|
||||||
|
|
||||||
|
@ -32,6 +33,8 @@ public:
|
||||||
|
|
||||||
void dump_tree(int indent = 0);
|
void dump_tree(int indent = 0);
|
||||||
|
|
||||||
|
void deferred_invoke(Function<void(GObject&)>);
|
||||||
|
|
||||||
virtual bool is_widget() const { return false; }
|
virtual bool is_widget() const { return false; }
|
||||||
virtual bool is_window() const { return false; }
|
virtual bool is_window() const { return false; }
|
||||||
|
|
||||||
|
|
|
@ -58,6 +58,11 @@ LIBGUI_OBJS = \
|
||||||
GFileSystemModel.o \
|
GFileSystemModel.o \
|
||||||
GSplitter.o \
|
GSplitter.o \
|
||||||
GTimer.o \
|
GTimer.o \
|
||||||
|
GNetworkJob.o \
|
||||||
|
GNetworkResponse.o \
|
||||||
|
GHttpRequest.o \
|
||||||
|
GHttpResponse.o \
|
||||||
|
GHttpNetworkJob.o \
|
||||||
GWindow.o
|
GWindow.o
|
||||||
|
|
||||||
OBJS = $(SHAREDGRAPHICS_OBJS) $(LIBGUI_OBJS)
|
OBJS = $(SHAREDGRAPHICS_OBJS) $(LIBGUI_OBJS)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue